NetCDF  4.9.3
pluginpath.md
1 Appendix E. NetCDF-4 Plugin Path Support {#pluginpaths}
2 ==================================
3 
4 [TOC]
5 
6 ## Plugin Path Overview {#pluginpaths_overview}
7 
8 The processes by which plugins are installed into some directory
9 and the process by which plugins are located are unfortunately
10 complicated. This is in part due to the historical requirements
11 to support existing HDF5 and Zarr mechanisms.
12 
13 This document describes the following major processes:
14 1. *Discovery* -- at run-time, any reference to a plugin must do a search
15 to locate a dynamic library that implements the plugin.
16 2. *Plugin Path Management* -- at run-time, the client program may wish to programmatically
17 set the sequence of directories to use in locating plugins.
18 3. *Installation* -- during the build of the netcdf-c library,
19 any compiled plugins may optionally be installed into some directory.
20 
21 ## Discovering a Specific Plugin at Run-Time
22 
23 The netcdf-c library maintains an internal sequence of directory paths
24 -- collectively called the *plugin path* -- that controls the search
25 for plugin libraries. Basically, when looking for a specific plugin,
26 each directory in the plugin path is examined in order. For each such
27 directory, the files in that directory are checked to see if it
28 contains the specified plugin. The details of how a file is processed
29 is described in the document *filters.md*.
30 
31 The netcdf-c search algorithm is closely tied to the HDF5
32 discovery process. The HDF5 process searches its own internal
33 plugin path (sequence of directories) in order to discover
34 a specific plugin library.
35 
36 The addition of NCZarr support to the netcdf-c library
37 requires yet another plugin path (sequence of directories)
38 for its search process.
39 
40 It is important to know that the plugin path is completely controlled
41 by a global plugin path. If it changes, then this global plugin path
42 is propagated to HDF5 and NCZarr to ensure that all such plugin paths
43 use the same sequence of directories for discovery.
44 
45 ## Programmatic Management of the Plugin Path
46 
47 As of netcdf-c version 4.9.3, it is possible for a client program
48 to set the global plugin path to control plugin discovery.
49 Since the global path and the HDF5 and NCZarr paths are kept in
50 sync, this means that both HDF5 and NCZarr will look in the same
51 directories in order to locate specified plugins.
52 [Appendix E.1](#pluginpath_appendixe1) defines the current API for
53 managing the global plugin path.
54 
55 Note that it is best practice for a client program to use the API
56 to set the plugin path before any calls to *nc_open* or *nc_create*.
57 Modifying the plugin paths later may fail because it cannot be guaranteed
58 that the underlying implementations (i.e. HDF5 or NCZarr) will
59 take notice of the change.
60 
61 When the netcdf-c library initializes itself, it chooses an initial
62 global plugin path using the following rules, which are those used
63 by the HDF5 library:
64 1. If *HDF5\_PLUGIN\_PATH* environment variable is defined,
65 then its value is used as the initial plugin path.
66 2. If *HDF5\_PLUGIN\_PATH* is not defined, then the
67 initial plugin path is either:
68  * /usr/local/hdf5/plugin -- for Linux/Unix/Cygwin,
69  * %ALLUSERSPROFILE%/hdf5/lib/plugin -- for Windows/Mingw.
70 
71 This initial global plugin path will be propagated to HDF5 and NCZarr.
72 
73 ## Installing Plugins at Build-Time
74 
75 At build-time, the target location directory into which libraries implementing plugins are installed is specified using a special *./configure* option
76 ````
77 --with-plugin-dir=<directorypath>
78 ````
79 or its corresponding *cmake* option.
80 ````
81 -DNETCDF_WITH_PLUGIN_DIR=<directorypath>
82 ````
83 
84 ## Build-Time Operations
85 
86 At build time, certain plugin-related constants are constructed.
87 1. NETCDF_PLUGIN_INSTALL_DIR -- the directory into which compiled plugins should be installed
88 2. NETCDF_PLUGIN_SEARCH_PATH -- the default search path to be used at run-time if not over-ridden by the *HDF5_PLUGIN_PATH* environment variable.
89 
90 <table style="border:2px solid black;border-collapse:collapse">
91 <tr style="outline: thin solid;" align="center"><td colspan="4">Table showing the build-time computation of DEFAULT_PLUGIN_INSTALL_DIR and DEFAULT_PLUGIN_SEARCH_PATH.</td>
92 <tr style="outline: thin solid" ><th>--with-plugin-dir<th>--prefix<th>DEFAULT_PLUGIN_INSTALL_DIR<th>DEFAULT_PLUGIN_SEARCH_PATH
93 <tr style="outline: thin solid" ><td>undefined<td>undefined<td>undefined<td>PLATFORMDEFALT
94 <tr style="outline: thin solid" ><td>undefined<td>&lt;abspath-prefix&gt;<td>&lt;abspath-prefix&gt;/hdf5/lib/plugin<td>&lt;abspath-prefix&gt;/hdf5/lib/plugin&lt;SEP&gt;PLATFORMDEFALT
95 <tr style="outline: thin solid" ><td>&lt;abspath-plugins&gt;<td>N.A.<td>&lt;abspath-plugins&gt;<td>&lt;abspath-plugins&gt;&lt;SEP&gt;PLATFORMDEFALT
96 </table>
97 
98 Notes:
99 1. HDF5_PLUGIN_PATH is ignored at build time.
100 
101 2. ';' is used as a placeholder for PLATFORMSEP.
102 
103 3. The term PLATFORMDEFAULT stands for:
104  - /usr/local/hdf5/lib/plugin If on a *nix* machine
105  - %ALLUSERSPROFILE%/hdf5/lib/plugins If on a windows or Mingw platform
106 4. The term SEP stands for:
107  - ':' If on a *nix* machine
108  - ';' If on a windows or Mingw platform
109 
110 ## Run-Time Operations
111 
112 When the netcdf-c library initializes itself (at runtime), it chooses an
113 initial global plugin path for the config.h value.
114 This value defaults to *NETCDF_PLUGIN_SEARCH_PATH*.
115 If, however, HDF5_PLUGIN_PATH is defined, then it is used to override
116 *NETCDF_PLUGIN_SEARCH_PATH*.
117 
118 <table style="border:2px solid black;border-collapse:collapse">
119 <tr style="outline: thin solid" align="center"><td colspan="2">Table showing the computation of the initial global plugin path</td>
120 <tr style="outline: thin solid"><th>HDF5_PLUGIN_PATH<th>Initial global plugin path
121 <tr style="outline: thin solid"><td>undefined<td>NETCDF_PLUGIN_SEARCH_PATH
122 <tr style="outline: thin solid"><td>&lt;path1;...pathn&gt;<td>&lt;path1;...pathn&gt;
123 </table>
124 
125 ## Multi-Threaded Access to the Plugin Path.
126 Specifically, note that modifying the plugin path must be done "atomically".
127 That is, in a multi-threaded environment, it is important that the sequence of actions involved in setting up the plugin path must be done by a single processor or in some other way as to guarantee that two or more processors are not simultaneously accessing the plugin path get/set operations.
128 
129 As an example, assume there exists a mutex lock called PLUGINLOCK.
130 Then any processor accessing the plugin paths should operate as follows:
131 ````
132 lock(PLUGINLOCK);
133 nc_plugin_path_get(...);
134 <rebuild plugin path>
135 nc_plugin_path_set(...);
136 unlock(PLUGINLOCK);
137 ````
138 
139 ## Internal Architecture
140 
141 It is assumed here that there only needs to be a single set of
142 plugin path directories that is shared by all filter code and is
143 independent of any file descriptor; it is global in other words.
144 This means, for example, that the path list for NCZarr and for
145 HDF5 will always be the same.
146 
147 However, and internally, processing the set of plugin paths
148 depends on the particular NC_FORMATX value (NC_FORMATX_NC_HDF5
149 and NC_FORMATX_NCZARR, currently). So the *nc_plugin_path_set*
150 function, will take the paths it is given and propagate them to
151 each of the NC_FORMATX dispatchers to store in a way that is
152 appropriate to the given dispatcher.
153 
154 There is a complication with respect to the *nc_plugin_path_get* function.
155 It is possible for users to bypass the netcdf API and modify the HDF5 plugin paths directly. This can result in an inconsistent plugin path between the value
156 used by HDF5 and the global value used by netcdf-c. Since there is no obvious fix for this, we warn the user of this possibility and otherwise ignore it.
157 
158 ## Appendix E.1. Programmatic Plugin Path API{#pluginpath_appendixe1}
159 
160 The API makes use of a counted vector of strings representing the sequence of directories in the path. The relevant type definition is as follows.
161 ````
162 typedef struct NCPluginList {size_t ndirs; char** dirs;} NCPluginList;
163 ````
164 
165 The API proposed in this PR looks like this (from netcdf-c/include/netcdf_filter.h).
166 
167 * ````int nc_plugin_path_ndirs(size_t* ndirsp);````
168 
169  This function returns the number of directories in the sequence if internal directories of the internal plugin path list.
170 
171  The argument is as follows:
172  - *ndirsp* store the number of directories in this memory.
173 
174 * ````int nc_plugin_path_get(NCPluginList* dirs);````
175 
176  This function returns the current sequence of directories from the internal plugin path list. Since this function does not modify the plugin path, it does not need to be locked; it is only when used to get the path to be modified that locking is required.
177 
178  The argument is as follows:
179  - *dirs* counted vector for storing the sequence of directies in the internal path list.
180 
181  If the value of *dirs.dirs is NULL (the normal case), then memory is allocated to hold the vector of directories. Otherwise, use the memory of *dirs.dirs* to hold the vector of directories.
182 
183 * ````int nc_plugin_path_set(const NCPluginList* dirs);````
184 
185  This function empties the current internal path sequence and replaces it with the sequence of directories argument. Using an *ndirs* argument of 0 will clear the set of plugin paths.
186 
187  The argument are as follows:
188  - *dirs* counted vector for storing the sequence of directies in the internal path list.
189 
190 *HDF5\_PLUGIN\_PATH* is a typical Windows or Unix style
191 path-list. That is it is a sequence of absolute directory paths
192 separated by a specific separator character. For Windows, the
193 separator character is a semicolon (';') and for Unix, it is a
194 colon (':').
195 
196 At the moment, NetCDF optionally (i.e. not overridden) uses the
197 existing HDF5 environment variable *HDF5\_PLUGIN\_PATH* to
198 locate the directories in which plugin libraries are located. It
199 also optionally uses the last directory in the path as the
200 installation directory. This is used both for the HDF5 filter
201 wrappers but also the NCZarr codec wrappers.
202 
203 ## History {#pluginpath_history}
204 
205 *Author*: Dennis Heimbigner<br>
206 *Email*: dennis.heimbigner@gmail.com<br>
207 *Initial Version*: 9/28/2024<br>
208 *Last Revised*: 9/28/2024