/src/netcdf-c/libdispatch/ddispatch.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata |
3 | | See LICENSE.txt for license information. |
4 | | */ |
5 | | |
6 | | #include "config.h" |
7 | | #include "ncdispatch.h" |
8 | | #include "ncuri.h" |
9 | | #include "nclog.h" |
10 | | #include "ncbytes.h" |
11 | | #include "ncrc.h" |
12 | | #include "ncoffsets.h" |
13 | | #include "ncpathmgr.h" |
14 | | #include "ncxml.h" |
15 | | #include "nc4internal.h" |
16 | | |
17 | | /* Required for getcwd, other functions. */ |
18 | | #ifdef HAVE_UNISTD_H |
19 | | #include <unistd.h> |
20 | | #endif |
21 | | |
22 | | /* Required for getcwd, other functions. */ |
23 | | #ifdef _WIN32 |
24 | | #include <direct.h> |
25 | | #endif |
26 | | |
27 | | #if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4) |
28 | | #include <curl/curl.h> |
29 | | #endif |
30 | | |
31 | | #ifdef NETCDF_ENABLE_S3 |
32 | | #include "ncs3sdk.h" |
33 | | #endif |
34 | | |
35 | 0 | #define MAXPATH 1024 |
36 | | |
37 | | /* Define vectors of zeros and ones for use with various nc_get_varX functions */ |
38 | | /* Note, this form of initialization fails under Cygwin */ |
39 | | size_t NC_coord_zero[NC_MAX_VAR_DIMS] = {0}; |
40 | | size_t NC_coord_one[NC_MAX_VAR_DIMS] = {1}; |
41 | | ptrdiff_t NC_stride_one[NC_MAX_VAR_DIMS] = {1}; |
42 | | |
43 | | /* |
44 | | static nc_type longtype = (sizeof(long) == sizeof(int)?NC_INT:NC_INT64); |
45 | | static nc_type ulongtype = (sizeof(unsigned long) == sizeof(unsigned int)?NC_UINT:NC_UINT64); |
46 | | */ |
47 | | |
48 | | /* Allow dispatch to do general initialization and finalization */ |
49 | | int |
50 | | NCDISPATCH_initialize(void) |
51 | 1 | { |
52 | 1 | int status = NC_NOERR; |
53 | 1 | int i; |
54 | 1 | NCglobalstate* globalstate = NULL; |
55 | | |
56 | 1.02k | for(i=0;i<NC_MAX_VAR_DIMS;i++) { |
57 | 1.02k | NC_coord_zero[i] = 0; |
58 | 1.02k | NC_coord_one[i] = 1; |
59 | 1.02k | NC_stride_one[i] = 1; |
60 | 1.02k | } |
61 | | |
62 | 1 | globalstate = NC_getglobalstate(); /* will allocate and clear */ |
63 | | |
64 | | /* Capture temp dir*/ |
65 | 1 | { |
66 | 1 | char* tempdir = NULL; |
67 | | #if defined _WIN32 || defined __MSYS__ || defined __CYGWIN__ |
68 | | tempdir = getenv("TEMP"); |
69 | | #else |
70 | 1 | tempdir = "/tmp"; |
71 | 1 | #endif |
72 | 1 | if(tempdir == NULL) { |
73 | 0 | fprintf(stderr,"Cannot find a temp dir; using ./\n"); |
74 | 0 | tempdir = "."; |
75 | 0 | } |
76 | 1 | globalstate->tempdir= strdup(tempdir); |
77 | 1 | } |
78 | | |
79 | | /* Capture $HOME */ |
80 | 1 | { |
81 | | #if defined(_WIN32) && !defined(__MINGW32__) |
82 | | char* home = getenv("USERPROFILE"); |
83 | | #else |
84 | 1 | char* home = getenv("HOME"); |
85 | 1 | #endif |
86 | 1 | if(home == NULL) { |
87 | | /* use cwd */ |
88 | 0 | home = malloc(MAXPATH+1); |
89 | 0 | NCgetcwd(home,MAXPATH); |
90 | 0 | } else |
91 | 1 | home = strdup(home); /* make it always free'able */ |
92 | 1 | assert(home != NULL); |
93 | 1 | NCpathcanonical(home,&globalstate->home); |
94 | 1 | nullfree(home); |
95 | 1 | } |
96 | | |
97 | | /* Capture $CWD */ |
98 | 1 | { |
99 | 1 | char cwdbuf[4096]; |
100 | | |
101 | 1 | cwdbuf[0] = '\0'; |
102 | 1 | (void)NCgetcwd(cwdbuf,sizeof(cwdbuf)); |
103 | | |
104 | 1 | if(strlen(cwdbuf) == 0) { |
105 | | /* use tempdir */ |
106 | 0 | strcpy(cwdbuf, globalstate->tempdir); |
107 | 0 | } |
108 | 1 | globalstate->cwd = strdup(cwdbuf); |
109 | 1 | } |
110 | | |
111 | 1 | ncloginit(); |
112 | | |
113 | | /* Now load RC Files */ |
114 | 1 | ncrc_initialize(); |
115 | | |
116 | | /* Compute type alignments */ |
117 | 1 | NC_compute_alignments(); |
118 | | |
119 | | #if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4) |
120 | | /* Initialize curl if it is being used */ |
121 | | { |
122 | | CURLcode cstat = curl_global_init(CURL_GLOBAL_ALL); |
123 | | if(cstat != CURLE_OK) |
124 | | status = NC_ECURL; |
125 | | } |
126 | | #endif |
127 | | |
128 | 1 | return status; |
129 | 1 | } |
130 | | |
131 | | int |
132 | | NCDISPATCH_finalize(void) |
133 | 1 | { |
134 | 1 | int status = NC_NOERR; |
135 | | #if defined(NETCDF_ENABLE_BYTERANGE) || defined(NETCDF_ENABLE_DAP) || defined(NETCDF_ENABLE_DAP4) |
136 | | curl_global_cleanup(); |
137 | | #endif |
138 | | #if defined(NETCDF_ENABLE_DAP4) |
139 | | ncxml_finalize(); |
140 | | #endif |
141 | 1 | NC_freeglobalstate(); /* should be one of the last things done */ |
142 | 1 | return status; |
143 | 1 | } |
144 | | |
145 | | /**************************************************/ |
146 | | /* Global State constants and state */ |
147 | | |
148 | | /* The singleton global state object */ |
149 | | static NCglobalstate* nc_globalstate = NULL; |
150 | | |
151 | | /* Forward */ |
152 | | static int NC_createglobalstate(void); |
153 | | |
154 | | /** \defgroup global_state Global state functions. */ |
155 | | /** \{ |
156 | | |
157 | | \ingroup global_state |
158 | | */ |
159 | | |
160 | | /* NCglobal state management */ |
161 | | |
162 | | static int |
163 | | NC_createglobalstate(void) |
164 | 1 | { |
165 | 1 | int stat = NC_NOERR; |
166 | 1 | const char* tmp = NULL; |
167 | | |
168 | 1 | if(nc_globalstate == NULL) { |
169 | 1 | nc_globalstate = calloc(1,sizeof(NCglobalstate)); |
170 | 1 | } |
171 | | /* Initialize struct pointers */ |
172 | 1 | if((nc_globalstate->rcinfo = calloc(1,sizeof(struct NCRCinfo)))==NULL) |
173 | 0 | {stat = NC_ENOMEM; goto done;} |
174 | 1 | if((nc_globalstate->rcinfo->entries = nclistnew())==NULL) |
175 | 0 | {stat = NC_ENOMEM; goto done;} |
176 | 1 | if((nc_globalstate->rcinfo->s3profiles = nclistnew())==NULL) |
177 | 0 | {stat = NC_ENOMEM; goto done;} |
178 | | |
179 | | /* Get environment variables */ |
180 | 1 | if(getenv(NCRCENVIGNORE) != NULL) |
181 | 0 | nc_globalstate->rcinfo->ignore = 1; |
182 | 1 | tmp = getenv(NCRCENVRC); |
183 | 1 | if(tmp != NULL && strlen(tmp) > 0) |
184 | 0 | nc_globalstate->rcinfo->rcfile = strdup(tmp); |
185 | | /* Initialize chunk cache defaults */ |
186 | 1 | nc_globalstate->chunkcache.size = DEFAULT_CHUNK_CACHE_SIZE; /**< Default chunk cache size. */ |
187 | 1 | nc_globalstate->chunkcache.nelems = DEFAULT_CHUNKS_IN_CACHE; /**< Default chunk cache number of elements. */ |
188 | 1 | nc_globalstate->chunkcache.preemption = DEFAULT_CHUNK_CACHE_PREEMPTION; /**< Default chunk cache preemption. */ |
189 | | |
190 | 1 | done: |
191 | 1 | return stat; |
192 | 1 | } |
193 | | |
194 | | /* Get global state */ |
195 | | NCglobalstate* |
196 | | NC_getglobalstate(void) |
197 | 11 | { |
198 | 11 | if(nc_globalstate == NULL) |
199 | 1 | NC_createglobalstate(); |
200 | 11 | return nc_globalstate; |
201 | 11 | } |
202 | | |
203 | | void |
204 | | NC_freeglobalstate(void) |
205 | 1 | { |
206 | 1 | if(nc_globalstate != NULL) { |
207 | 1 | nullfree(nc_globalstate->tempdir); |
208 | 1 | nullfree(nc_globalstate->home); |
209 | 1 | nullfree(nc_globalstate->cwd); |
210 | 1 | nullfree(nc_globalstate->aws.default_region); |
211 | 1 | nullfree(nc_globalstate->aws.config_file); |
212 | 1 | nullfree(nc_globalstate->aws.profile); |
213 | 1 | nullfree(nc_globalstate->aws.access_key_id); |
214 | 1 | nullfree(nc_globalstate->aws.secret_access_key); |
215 | 1 | if(nc_globalstate->rcinfo) { |
216 | 1 | NC_rcclear(nc_globalstate->rcinfo); |
217 | 1 | free(nc_globalstate->rcinfo); |
218 | 1 | } |
219 | 1 | nclistfree(nc_globalstate->pluginpaths); |
220 | 1 | free(nc_globalstate); |
221 | 1 | nc_globalstate = NULL; |
222 | 1 | } |
223 | 1 | } |
224 | | |
225 | | /** \} */ |
226 | | |
227 | | /**************************************************/ |
228 | | /** \defgroup atomic_types Atomic Type functions */ |
229 | | /** \{ |
230 | | |
231 | | \ingroup atomic_types |
232 | | */ |
233 | | |
234 | | /* The sizes of types may vary from platform to platform, but within |
235 | | * netCDF files, type sizes are fixed. */ |
236 | | #define NC_CHAR_LEN sizeof(char) /**< @internal Size of char. */ |
237 | | #define NC_STRING_LEN sizeof(char *) /**< @internal Size of char *. */ |
238 | | #define NC_BYTE_LEN 1 /**< @internal Size of byte. */ |
239 | | #define NC_SHORT_LEN 2 /**< @internal Size of short. */ |
240 | | #define NC_INT_LEN 4 /**< @internal Size of int. */ |
241 | | #define NC_FLOAT_LEN 4 /**< @internal Size of float. */ |
242 | | #define NC_DOUBLE_LEN 8 /**< @internal Size of double. */ |
243 | | #define NC_INT64_LEN 8 /**< @internal Size of int64. */ |
244 | | |
245 | | /** @internal Names of atomic types. */ |
246 | | const char* nc4_atomic_name[NUM_ATOMIC_TYPES] = {"none", "byte", "char", |
247 | | "short", "int", "float", |
248 | | "double", "ubyte", |
249 | | "ushort", "uint", |
250 | | "int64", "uint64", "string"}; |
251 | | static const size_t nc4_atomic_size[NUM_ATOMIC_TYPES] = {0, NC_BYTE_LEN, NC_CHAR_LEN, NC_SHORT_LEN, |
252 | | NC_INT_LEN, NC_FLOAT_LEN, NC_DOUBLE_LEN, |
253 | | NC_BYTE_LEN, NC_SHORT_LEN, NC_INT_LEN, NC_INT64_LEN, |
254 | | NC_INT64_LEN, NC_STRING_LEN}; |
255 | | |
256 | | /** |
257 | | * @internal Get the name and size of an atomic type. For strings, 1 is |
258 | | * returned. |
259 | | * |
260 | | * @param typeid1 Type ID. |
261 | | * @param name Gets the name of the type. |
262 | | * @param size Gets the size of one element of the type in bytes. |
263 | | * |
264 | | * @return ::NC_NOERR No error. |
265 | | * @return ::NC_EBADID Bad ncid. |
266 | | * @return ::NC_EBADTYPE Type not found. |
267 | | * @author Dennis Heimbigner |
268 | | */ |
269 | | int |
270 | | NC4_inq_atomic_type(nc_type typeid1, char *name, size_t *size) |
271 | 0 | { |
272 | 0 | if (typeid1 >= NUM_ATOMIC_TYPES) |
273 | 0 | return NC_EBADTYPE; |
274 | 0 | if (name) |
275 | 0 | strcpy(name, nc4_atomic_name[typeid1]); |
276 | 0 | if (size) |
277 | 0 | *size = nc4_atomic_size[typeid1]; |
278 | 0 | return NC_NOERR; |
279 | 0 | } |
280 | | |
281 | | /** |
282 | | * @internal Get the id and size of an atomic type by name. |
283 | | * |
284 | | * @param name [in] the name of the type. |
285 | | * @param idp [out] the type index of the type. |
286 | | * @param sizep [out] the size of one element of the type in bytes. |
287 | | * |
288 | | * @return ::NC_NOERR No error. |
289 | | * @return ::NC_EBADID Bad ncid. |
290 | | * @return ::NC_EBADTYPE Type not found. |
291 | | * @author Dennis Heimbigner |
292 | | */ |
293 | | int |
294 | | NC4_lookup_atomic_type(const char *name, nc_type* idp, size_t *sizep) |
295 | 0 | { |
296 | 0 | int i; |
297 | |
|
298 | 0 | if (name == NULL || strlen(name) == 0) |
299 | 0 | return NC_EBADTYPE; |
300 | 0 | for(i=0;i<NUM_ATOMIC_TYPES;i++) { |
301 | 0 | if(strcasecmp(name,nc4_atomic_name[i])==0) { |
302 | 0 | if(idp) *idp = i; |
303 | 0 | if(sizep) *sizep = nc4_atomic_size[i]; |
304 | 0 | return NC_NOERR; |
305 | 0 | } |
306 | 0 | } |
307 | 0 | return NC_EBADTYPE; |
308 | 0 | } |
309 | | |
310 | | /** |
311 | | * @internal Get the id of an atomic type from the name. |
312 | | * |
313 | | * @param ncid File and group ID. |
314 | | * @param name Name of type |
315 | | * @param typeidp Pointer that will get the type ID. |
316 | | * |
317 | | * @return ::NC_NOERR No error. |
318 | | * @return ::NC_EBADTYPE Type not found. |
319 | | * @author Ed Hartnett |
320 | | */ |
321 | | int |
322 | | NC4_inq_atomic_typeid(int ncid, const char *name, nc_type *typeidp) |
323 | 0 | { |
324 | 0 | int i; |
325 | |
|
326 | 0 | NC_UNUSED(ncid); |
327 | | |
328 | | /* Handle atomic types. */ |
329 | 0 | for (i = 0; i < NUM_ATOMIC_TYPES; i++) { |
330 | 0 | if (!strcmp(name, nc4_atomic_name[i])) |
331 | 0 | { |
332 | 0 | if (typeidp) |
333 | 0 | *typeidp = i; |
334 | 0 | return NC_NOERR; |
335 | 0 | } |
336 | 0 | } |
337 | 0 | return NC_EBADTYPE; |
338 | 0 | } |
339 | | |
340 | | /** |
341 | | * @internal Get the class of a type |
342 | | * |
343 | | * @param xtype NetCDF type ID. |
344 | | * @param type_class Pointer that gets class of type, NC_INT, |
345 | | * NC_FLOAT, NC_CHAR, or NC_STRING, NC_ENUM, NC_VLEN, NC_COMPOUND, or |
346 | | * NC_OPAQUE. |
347 | | * |
348 | | * @return ::NC_NOERR No error. |
349 | | * @author Ed Hartnett, Dennis Heimbigner |
350 | | */ |
351 | | int |
352 | | NC4_get_atomic_typeclass(nc_type xtype, int *type_class) |
353 | 0 | { |
354 | 0 | assert(type_class); |
355 | 0 | switch (xtype) { |
356 | 0 | case NC_BYTE: |
357 | 0 | case NC_UBYTE: |
358 | 0 | case NC_SHORT: |
359 | 0 | case NC_USHORT: |
360 | 0 | case NC_INT: |
361 | 0 | case NC_UINT: |
362 | 0 | case NC_INT64: |
363 | 0 | case NC_UINT64: |
364 | | /* NC_INT is class used for all integral types */ |
365 | 0 | *type_class = NC_INT; |
366 | 0 | break; |
367 | 0 | case NC_FLOAT: |
368 | 0 | case NC_DOUBLE: |
369 | | /* NC_FLOAT is class used for all floating-point types */ |
370 | 0 | *type_class = NC_FLOAT; |
371 | 0 | break; |
372 | 0 | case NC_CHAR: |
373 | 0 | *type_class = NC_CHAR; |
374 | 0 | break; |
375 | 0 | case NC_STRING: |
376 | 0 | *type_class = NC_STRING; |
377 | 0 | break; |
378 | 0 | default: |
379 | 0 | return NC_EBADTYPE; |
380 | 0 | } |
381 | 0 | return NC_NOERR; |
382 | 0 | } |
383 | | |
384 | | /** \} */ |
385 | | |
386 | | /**************************************************/ |
387 | | /** \defgroup alignment Alignment functions. */ |
388 | | |
389 | | /** \{ |
390 | | |
391 | | \ingroup alignment |
392 | | */ |
393 | | |
394 | | /** |
395 | | Provide a function to store global data alignment |
396 | | information. |
397 | | Repeated calls to nc_set_alignment will overwrite any existing values. |
398 | | |
399 | | If defined, then for every file created or opened after the call to |
400 | | nc_set_alignment, and for every new variable added to the file, the |
401 | | most recently set threshold and alignment values will be applied |
402 | | to that variable. |
403 | | |
404 | | The nc_set_alignment function causes new data written to a |
405 | | netCDF-4 file to be aligned on disk to a specified block |
406 | | size. To be effective, alignment should be the system disk block |
407 | | size, or a multiple of it. This setting is effective with MPI |
408 | | I/O and other parallel systems. |
409 | | |
410 | | This is a trade-off of write speed versus file size. Alignment |
411 | | leaves holes between file objects. The default of no alignment |
412 | | writes file objects contiguously, without holes. Alignment has |
413 | | no impact on file readability. |
414 | | |
415 | | Alignment settings apply only indirectly, through the file open |
416 | | functions. Call nc_set_alignment first, then nc_create or |
417 | | nc_open for one or more files. Current alignment settings are |
418 | | locked in when each file is opened, then forgotten when the same |
419 | | file is closed. For illustration, it is possible to write |
420 | | different files at the same time with different alignments, by |
421 | | interleaving nc_set_alignment and nc_open calls. |
422 | | |
423 | | Alignment applies to all newly written low-level file objects at |
424 | | or above the threshold size, including chunks of variables, |
425 | | attributes, and internal infrastructure. Alignment is not locked |
426 | | in to a data variable. It can change between data chunks of the |
427 | | same variable, based on a file's history. |
428 | | |
429 | | Refer to H5Pset_alignment in HDF5 documentation for more |
430 | | specific details, interactions, and additional rules. |
431 | | |
432 | | @param threshold The minimum size to which alignment is applied. |
433 | | @param alignment The alignment value. |
434 | | |
435 | | @return ::NC_NOERR No error. |
436 | | @return ::NC_EINVAL Invalid input. |
437 | | @author Dennis Heimbigner |
438 | | @ingroup datasets |
439 | | */ |
440 | | int |
441 | | nc_set_alignment(int threshold, int alignment) |
442 | 0 | { |
443 | 0 | NCglobalstate* gs = NC_getglobalstate(); |
444 | 0 | gs->alignment.threshold = threshold; |
445 | 0 | gs->alignment.alignment = alignment; |
446 | 0 | gs->alignment.defined = 1; |
447 | 0 | return NC_NOERR; |
448 | 0 | } |
449 | | |
450 | | /** |
451 | | Provide get function to retrieve global data alignment |
452 | | information. |
453 | | |
454 | | The nc_get_alignment function return the last values set by |
455 | | nc_set_alignment. If nc_set_alignment has not been called, then |
456 | | it returns the value 0 for both threshold and alignment. |
457 | | |
458 | | @param thresholdp Return the current minimum size to which alignment is applied or zero. |
459 | | @param alignmentp Return the current alignment value or zero. |
460 | | |
461 | | @return ::NC_NOERR No error. |
462 | | @return ::NC_EINVAL Invalid input. |
463 | | @author Dennis Heimbigner |
464 | | @ingroup datasets |
465 | | */ |
466 | | |
467 | | int |
468 | | nc_get_alignment(int* thresholdp, int* alignmentp) |
469 | 0 | { |
470 | 0 | NCglobalstate* gs = NC_getglobalstate(); |
471 | 0 | if(thresholdp) *thresholdp = gs->alignment.threshold; |
472 | 0 | if(alignmentp) *alignmentp = gs->alignment.alignment; |
473 | 0 | return NC_NOERR; |
474 | 0 | } |
475 | | |
476 | | /** \} */ |