source: XIOS/dev/dev_cmip6_omp/extern/src_netcdf4/nc.c @ 1606

Last change on this file since 1606 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 31.2 KB
Line 
1/*
2 *      Copyright 1996, University Corporation for Atmospheric Research
3 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 */
5
6#include <config.h>
7#include <stdlib.h>
8#include <string.h>
9#include <assert.h>
10#if defined(LOCKNUMREC) /* && _CRAYMPP */
11#  include <mpp/shmem.h>
12#  include <intrinsics.h>
13#endif
14#ifdef HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17
18#include "nc.h"
19#include "ncdispatch.h"
20#include "nc3dispatch.h"
21#include "rnd.h"
22#include "ncx.h"
23
24/* This is the default create format for nc_create and nc__create. */
25int default_create_format = NC_FORMAT_CLASSIC;
26
27/* These have to do with version numbers. */
28#define MAGIC_NUM_LEN 4
29#define VER_CLASSIC 1
30#define VER_64BIT_OFFSET 2
31#define VER_HDF5 3
32
33int
34NC_check_id(int ncid, NC **ncpp)
35{
36    NC* nc = find_in_NCList(ncid);
37    if(nc == NULL) return NC_EBADID;
38    if(ncpp) *ncpp = nc;
39    return NC_NOERR;
40}
41
42static void
43free_NC(NC *ncp)
44{
45        if(ncp == NULL)
46                return;
47        free_NC_dimarrayV(&ncp->dims);
48        free_NC_attrarrayV(&ncp->attrs);
49        free_NC_vararrayV(&ncp->vars);
50        if (ncp->path)
51           free(ncp->path);
52#if _CRAYMPP && defined(LOCKNUMREC)
53        shfree(ncp);
54#else
55        free(ncp);
56#endif /* _CRAYMPP && LOCKNUMREC */
57}
58
59static NC *
60new_NC(const size_t *chunkp, NC_Dispatch* dispatch)
61{
62        NC *ncp;
63        int stat = dispatch->new_nc(&ncp);
64        if(stat) return NULL;
65        ncp->xsz = MIN_NC_XSZ;
66        assert(ncp->xsz == ncx_len_NC(ncp,0));
67        ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT;
68        return ncp;
69}
70
71static NC *
72dup_NC(const NC *ref)
73{
74        NC *ncp;
75        int stat = ref->dispatch->new_nc(&ncp);
76        if(stat) return NULL;
77        if(ncp == NULL)
78                return NULL;
79
80        if(dup_NC_dimarrayV(&ncp->dims, &ref->dims) != NC_NOERR)
81                goto err;
82        if(dup_NC_attrarrayV(&ncp->attrs, &ref->attrs) != NC_NOERR)
83                goto err;
84        if(dup_NC_vararrayV(&ncp->vars, &ref->vars) != NC_NOERR)
85                goto err;
86
87        ncp->xsz = ref->xsz;
88        ncp->begin_var = ref->begin_var;
89        ncp->begin_rec = ref->begin_rec;
90        ncp->recsize = ref->recsize;
91        NC_set_numrecs(ncp, NC_get_numrecs(ref));
92        return ncp;
93err:
94        free_NC(ncp);
95        return NULL;
96}
97
98
99/*
100 *  Verify that this is a user nc_type
101 * Formerly
102NCcktype()
103 * Sense of the return is changed.
104 */
105int
106nc_cktype(nc_type type)
107{
108        switch((int)type){
109        case NC_BYTE:
110        case NC_CHAR:
111        case NC_SHORT:
112        case NC_INT:
113        case NC_FLOAT:
114        case NC_DOUBLE:
115                return(NC_NOERR);
116        }
117        return(NC_EBADTYPE);
118}
119
120
121/*
122 * How many objects of 'type'
123 * will fit into xbufsize?
124 */
125size_t
126ncx_howmany(nc_type type, size_t xbufsize)
127{
128        switch(type){
129        case NC_BYTE:
130        case NC_CHAR:
131                return xbufsize;
132        case NC_SHORT:
133                return xbufsize/X_SIZEOF_SHORT;
134        case NC_INT:
135                return xbufsize/X_SIZEOF_INT;
136        case NC_FLOAT:
137                return xbufsize/X_SIZEOF_FLOAT;
138        case NC_DOUBLE:
139                return xbufsize/X_SIZEOF_DOUBLE;
140        default:
141                assert("ncx_howmany: Bad type" == 0);
142                return(0);
143        }
144}
145
146#define D_RNDUP(x, align) _RNDUP(x, (off_t)(align))
147
148/*
149 * Compute each variable's 'begin' offset,
150 * update 'begin_rec' as well.
151 */
152static int
153NC_begins(NC *ncp,
154        size_t h_minfree, size_t v_align,
155        size_t v_minfree, size_t r_align)
156{
157        size_t ii;
158        int sizeof_off_t;
159        off_t index = 0;
160        NC_var **vpp;
161        NC_var *last = NULL;
162
163        if(v_align == NC_ALIGN_CHUNK)
164                v_align = ncp->chunk;
165        if(r_align == NC_ALIGN_CHUNK)
166                r_align = ncp->chunk;
167
168        if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) {
169          sizeof_off_t = 8;
170        } else {
171          sizeof_off_t = 4;
172        }
173       
174        ncp->xsz = ncx_len_NC(ncp,sizeof_off_t);
175
176        if(ncp->vars.nelems == 0) 
177                return NC_NOERR;
178
179        /* only (re)calculate begin_var if there is not sufficient space in header
180           or start of non-record variables is not aligned as requested by valign */
181        if (ncp->begin_var < ncp->xsz + h_minfree ||
182            ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) ) 
183        {
184          index = (off_t) ncp->xsz;
185          ncp->begin_var = D_RNDUP(index, v_align);
186          if(ncp->begin_var < index + h_minfree)
187          {
188            ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align);
189          }
190        }
191        index = ncp->begin_var;
192
193        /* loop thru vars, first pass is for the 'non-record' vars */
194        vpp = ncp->vars.value;
195        for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++)
196        {
197                if( IS_RECVAR(*vpp) )
198                {
199                        /* skip record variables on this pass */
200                        continue;
201                }
202#if 0
203fprintf(stderr, "    VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
204#endif
205                if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) ) 
206                {
207                    return NC_EVARSIZE;
208                }
209                (*vpp)->begin = index;
210                index += (*vpp)->len;
211        }
212
213        /* only (re)calculate begin_rec if there is not sufficient
214           space at end of non-record variables or if start of record
215           variables is not aligned as requested by r_align */
216        if (ncp->begin_rec < index + v_minfree ||
217            ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) )
218        {
219          ncp->begin_rec = D_RNDUP(index, r_align);
220          if(ncp->begin_rec < index + v_minfree)
221          {
222            ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align);
223          }
224        }
225        index = ncp->begin_rec;
226
227        ncp->recsize = 0;
228
229        /* loop thru vars, second pass is for the 'record' vars */
230        vpp = (NC_var **)ncp->vars.value;
231        for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++)
232        {
233                if( !IS_RECVAR(*vpp) )
234                {
235                        /* skip non-record variables on this pass */
236                        continue;
237                }
238
239#if 0
240fprintf(stderr, "    REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
241#endif
242                if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) ) 
243                {
244                    return NC_EVARSIZE;
245                }
246                (*vpp)->begin = index;
247                index += (*vpp)->len;
248                /* check if record size must fit in 32-bits */
249#if SIZEOF_OFF_T == SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4
250                if( ncp->recsize > X_UINT_MAX - (*vpp)->len )
251                {
252                    return NC_EVARSIZE;
253                }
254#endif
255                if((*vpp)->len != UINT32_MAX) /* flag for vars >= 2**32 bytes */
256                    ncp->recsize += (*vpp)->len;
257                last = (*vpp);
258        }
259
260        /*
261         * for special case of
262         */
263        if(last != NULL) {
264            if(ncp->recsize == last->len) { /* exactly one record variable, pack value */
265                ncp->recsize = *last->dsizes * last->xsz;
266            } else if(last->len == UINT32_MAX) { /* huge last record variable */
267                ncp->recsize += *last->dsizes * last->xsz;
268            }
269        }
270        if(NC_IsNew(ncp))
271                NC_set_numrecs(ncp, 0);
272        return NC_NOERR;
273}
274
275
276/*
277 * Read just the numrecs member.
278 * (A relatively expensive way to do things.)
279 */
280int
281read_numrecs(NC *ncp)
282{
283        int status = NC_NOERR;
284        const void *xp = NULL;
285        size_t nrecs = NC_get_numrecs(ncp);
286
287        assert(!NC_indef(ncp));
288
289#define NC_NUMRECS_OFFSET 4
290#define NC_NUMRECS_EXTENT 4
291        status = ncio_get(ncp->nciop,
292                 NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, 0, (void **)&xp);
293                                        /* cast away const */
294        if(status != NC_NOERR)
295                return status;
296
297        status = ncx_get_size_t(&xp, &nrecs);
298
299        (void) ncio_rel(ncp->nciop, NC_NUMRECS_OFFSET, 0);
300
301        if(status == NC_NOERR)
302        {
303                NC_set_numrecs(ncp, nrecs);
304                fClr(ncp->flags, NC_NDIRTY);
305        }
306
307        return status;
308}
309
310
311/*
312 * Write out just the numrecs member.
313 * (A relatively expensive way to do things.)
314 */
315int
316write_numrecs(NC *ncp)
317{
318        int status = NC_NOERR;
319        void *xp = NULL;
320
321        assert(!NC_readonly(ncp));
322        assert(!NC_indef(ncp));
323
324        status = ncio_get(ncp->nciop,
325                 NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, RGN_WRITE, &xp);
326        if(status != NC_NOERR)
327                return status;
328
329        {
330                const size_t nrecs = NC_get_numrecs(ncp);
331                status = ncx_put_size_t(&xp, &nrecs);
332        }
333
334        (void) ncio_rel(ncp->nciop, NC_NUMRECS_OFFSET, RGN_MODIFIED);
335
336        if(status == NC_NOERR)
337                fClr(ncp->flags, NC_NDIRTY);
338
339        return status;
340}
341
342
343/*
344 * Read in the header
345 * It is expensive.
346 */
347static int
348read_NC(NC *ncp)
349{
350        int status = NC_NOERR;
351
352        free_NC_dimarrayV(&ncp->dims);
353        free_NC_attrarrayV(&ncp->attrs);
354        free_NC_vararrayV(&ncp->vars);
355
356        status = nc_get_NC(ncp);
357
358        if(status == NC_NOERR)
359                fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
360
361        return status;
362}
363
364
365/*
366 * Write out the header
367 */
368static int
369write_NC(NC *ncp)
370{
371        int status = NC_NOERR;
372
373        assert(!NC_readonly(ncp));
374
375        status = ncx_put_NC(ncp, NULL, 0, 0);
376
377        if(status == NC_NOERR)
378                fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
379
380        return status;
381}
382
383
384/*
385 * Write the header or the numrecs if necessary.
386 */
387int
388NC_sync(NC *ncp)
389{
390        assert(!NC_readonly(ncp));
391
392        if(NC_hdirty(ncp))
393        {
394                return write_NC(ncp);
395        }
396        /* else */
397
398        if(NC_ndirty(ncp))
399        {
400                return write_numrecs(ncp);
401        }
402        /* else */
403
404        return NC_NOERR;
405}
406
407
408/*
409 * Initialize the 'non-record' variables.
410 */
411static int
412fillerup(NC *ncp)
413{
414        int status = NC_NOERR;
415        size_t ii;
416        NC_var **varpp;
417
418        assert(!NC_readonly(ncp));
419        assert(NC_dofill(ncp));
420
421        /* loop thru vars */
422        varpp = ncp->vars.value;
423        for(ii = 0; ii < ncp->vars.nelems; ii++, varpp++)
424        {
425                if(IS_RECVAR(*varpp))
426                {
427                        /* skip record variables */
428                        continue;
429                }
430
431                status = fill_NC_var(ncp, *varpp, (*varpp)->len, 0);
432                if(status != NC_NOERR)
433                        break;
434        }
435        return status;
436}
437
438/* Begin endef */
439
440/*
441 */
442static int
443fill_added_recs(NC *gnu, NC *old)
444{
445        NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
446
447        const int old_nrecs = (int) NC_get_numrecs(old);
448        int recno = 0;
449        NC_var **vpp = gnu_varpp;
450        NC_var *const *const end = &vpp[gnu->vars.nelems];
451        int numrecvars = 0;
452
453        /* Determine if there is only one record variable.  If so, we
454           must treat as a special case because there's no record padding */
455        for(; vpp < end; vpp++) {
456            if(IS_RECVAR(*vpp)) {
457                numrecvars++;
458            }
459        }
460
461        for(; recno < old_nrecs; recno++)
462            {
463                int varid = (int)old->vars.nelems;
464                for(; varid < (int)gnu->vars.nelems; varid++)
465                    {
466                        const NC_var *const gnu_varp = *(gnu_varpp + varid);
467                        if(!IS_RECVAR(gnu_varp))
468                            {
469                                /* skip non-record variables */
470                                continue;
471                            }
472                        /* else */
473                        {
474                            size_t varsize = numrecvars == 1 ? gnu->recsize :  gnu_varp->len;
475                            const int status = fill_NC_var(gnu, gnu_varp, varsize, recno);
476                            if(status != NC_NOERR)
477                                return status;
478                        }
479                    }
480            }
481        return NC_NOERR;
482}
483
484/*
485 */
486static int
487fill_added(NC *gnu, NC *old)
488{
489        NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
490        int varid = (int)old->vars.nelems;
491
492        for(; varid < (int)gnu->vars.nelems; varid++)
493        {
494                const NC_var *const gnu_varp = *(gnu_varpp + varid);
495                if(IS_RECVAR(gnu_varp))
496                {
497                        /* skip record variables */
498                        continue;
499                }
500                /* else */
501                {
502                const int status = fill_NC_var(gnu, gnu_varp, gnu_varp->len, 0);
503                if(status != NC_NOERR)
504                        return status;
505                }
506        }
507
508        return NC_NOERR;
509}
510
511
512/*
513 * Move the records "out".
514 * Fill as needed.
515 */
516static int
517move_recs_r(NC *gnu, NC *old)
518{
519        int status;
520        int recno;
521        int varid;
522        NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
523        NC_var **old_varpp = (NC_var **)old->vars.value;
524        NC_var *gnu_varp;
525        NC_var *old_varp;
526        off_t gnu_off;
527        off_t old_off;
528        const size_t old_nrecs = NC_get_numrecs(old);
529       
530        /* Don't parallelize this loop */
531        for(recno = (int)old_nrecs -1; recno >= 0; recno--)
532        {
533        /* Don't parallelize this loop */
534        for(varid = (int)old->vars.nelems -1; varid >= 0; varid--)
535        {
536                gnu_varp = *(gnu_varpp + varid);
537                if(!IS_RECVAR(gnu_varp))
538                {
539                        /* skip non-record variables on this pass */
540                        continue;
541                }
542                /* else */
543
544                /* else, a pre-existing variable */
545                old_varp = *(old_varpp + varid);
546                gnu_off = gnu_varp->begin + (off_t)(gnu->recsize * recno);
547                old_off = old_varp->begin + (off_t)(old->recsize * recno);
548
549                if(gnu_off == old_off)
550                        continue;       /* nothing to do */
551
552                assert(gnu_off > old_off);
553       
554                status = ncio_move(gnu->nciop, gnu_off, old_off,
555                         old_varp->len, 0);
556
557                if(status != NC_NOERR)
558                        return status;
559               
560        }
561        }
562
563        NC_set_numrecs(gnu, old_nrecs);
564
565        return NC_NOERR;
566}
567
568
569/*
570 * Move the "non record" variables "out".
571 * Fill as needed.
572 */
573static int
574move_vars_r(NC *gnu, NC *old)
575{
576        int status;
577        int varid;
578        NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
579        NC_var **old_varpp = (NC_var **)old->vars.value;
580        NC_var *gnu_varp;
581        NC_var *old_varp;
582        off_t gnu_off;
583        off_t old_off;
584       
585        /* Don't parallelize this loop */
586        for(varid = (int)old->vars.nelems -1;
587                 varid >= 0; varid--)
588        {
589                gnu_varp = *(gnu_varpp + varid);
590                if(IS_RECVAR(gnu_varp))
591                {
592                        /* skip record variables on this pass */
593                        continue;
594                }
595                /* else */
596
597                old_varp = *(old_varpp + varid);
598                gnu_off = gnu_varp->begin;
599                old_off = old_varp->begin;
600       
601                if(gnu_off == old_off)
602                        continue;       /* nothing to do */
603
604                assert(gnu_off > old_off);
605
606                status = ncio_move(gnu->nciop, gnu_off, old_off,
607                         old_varp->len, 0);
608
609                if(status != NC_NOERR)
610                        return status;
611               
612        }
613
614        return NC_NOERR;
615}
616
617
618/*
619 * Given a valid ncp, return NC_EVARSIZE if any variable has a bad len
620 * (product of non-rec dim sizes too large), else return NC_NOERR.
621 */
622static int
623NC_check_vlens(NC *ncp)
624{
625    NC_var **vpp;
626    /* maximum permitted variable size (or size of one record's worth
627       of a record variable) in bytes.  This is different for format 1
628       and format 2. */
629    size_t vlen_max;
630    size_t ii;
631    size_t large_vars_count;
632    size_t rec_vars_count;
633    int last = 0;
634
635    if(ncp->vars.nelems == 0) 
636        return NC_NOERR;
637
638    if ((ncp->flags & NC_64BIT_OFFSET) && sizeof(off_t) > 4) {
639        /* CDF2 format and LFS */
640        vlen_max = X_UINT_MAX - 3; /* "- 3" handles rounded-up size */
641    } else {
642        /* CDF1 format */
643        vlen_max = X_INT_MAX - 3;
644    }
645    /* Loop through vars, first pass is for non-record variables.   */
646    large_vars_count = 0;
647    rec_vars_count = 0;
648    vpp = ncp->vars.value;
649    for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
650        if( !IS_RECVAR(*vpp) ) {
651            last = 0;
652            if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
653                large_vars_count++;
654                last = 1;
655            }
656        } else {
657          rec_vars_count++;
658        }
659    }
660    /* OK if last non-record variable size too large, since not used to
661       compute an offset */
662    if( large_vars_count > 1) { /* only one "too-large" variable allowed */
663      return NC_EVARSIZE;
664    }
665    /* and it has to be the last one */ 
666    if( large_vars_count == 1 && last == 0) { 
667      return NC_EVARSIZE;
668    }
669    if( rec_vars_count > 0 ) {
670        /* and if it's the last one, there can't be any record variables */
671        if( large_vars_count == 1 && last == 1) {
672            return NC_EVARSIZE;
673        }
674        /* Loop through vars, second pass is for record variables.   */
675        large_vars_count = 0;
676        vpp = ncp->vars.value;
677        for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
678            if( IS_RECVAR(*vpp) ) {
679                last = 0;
680                if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
681                    large_vars_count++;
682                    last = 1;
683                }
684            }
685        }
686        /* OK if last record variable size too large, since not used to
687           compute an offset */
688        if( large_vars_count > 1) { /* only one "too-large" variable allowed */
689            return NC_EVARSIZE;
690        }
691        /* and it has to be the last one */ 
692        if( large_vars_count == 1 && last == 0) { 
693            return NC_EVARSIZE;
694        }
695    }
696    return NC_NOERR;
697}
698
699
700/*
701 *  End define mode.
702 *  Common code for ncendef, ncclose(endef)
703 *  Flushes I/O buffers.
704 */
705static int
706NC_endef(NC *ncp,
707        size_t h_minfree, size_t v_align,
708        size_t v_minfree, size_t r_align)
709{
710        int status = NC_NOERR;
711
712        assert(!NC_readonly(ncp));
713        assert(NC_indef(ncp));
714
715        status = NC_check_vlens(ncp);
716        if(status != NC_NOERR)
717            return status;
718        status = NC_begins(ncp, h_minfree, v_align, v_minfree, r_align);
719        if(status != NC_NOERR)
720            return status;
721
722        if(ncp->old != NULL)
723        {
724                /* a plain redef, not a create */
725                assert(!NC_IsNew(ncp));
726                assert(fIsSet(ncp->flags, NC_INDEF));
727                assert(ncp->begin_rec >= ncp->old->begin_rec);
728                assert(ncp->begin_var >= ncp->old->begin_var);
729
730                if(ncp->vars.nelems != 0)
731                {
732                if(ncp->begin_rec > ncp->old->begin_rec)
733                {
734                        status = move_recs_r(ncp, ncp->old);
735                        if(status != NC_NOERR)
736                                return status;
737                        if(ncp->begin_var > ncp->old->begin_var)
738                        {
739                                status = move_vars_r(ncp, ncp->old);
740                                if(status != NC_NOERR)
741                                        return status;
742                        } 
743                        /* else if (ncp->begin_var == ncp->old->begin_var) { NOOP } */
744                }
745                else
746                {       /* Even if (ncp->begin_rec == ncp->old->begin_rec)
747                           and     (ncp->begin_var == ncp->old->begin_var)
748                           might still have added a new record variable */
749                        if(ncp->recsize > ncp->old->recsize)
750                        {
751                                status = move_recs_r(ncp, ncp->old);
752                                if(status != NC_NOERR)
753                                      return status;
754                        }
755                }
756                }
757        }
758
759        status = write_NC(ncp);
760        if(status != NC_NOERR)
761                return status;
762
763        if(NC_dofill(ncp))
764        {
765                if(NC_IsNew(ncp))
766                {
767                        status = fillerup(ncp);
768                        if(status != NC_NOERR)
769                                return status;
770                       
771                }
772                else if(ncp->vars.nelems > ncp->old->vars.nelems)
773                {
774                        status = fill_added(ncp, ncp->old);
775                        if(status != NC_NOERR)
776                                return status;
777                        status = fill_added_recs(ncp, ncp->old);
778                        if(status != NC_NOERR)
779                                return status;
780                }
781        }
782
783        if(ncp->old != NULL)
784        {
785                free_NC(ncp->old);
786                ncp->old = NULL;
787        }
788
789        fClr(ncp->flags, NC_CREAT | NC_INDEF);
790
791        return ncio_sync(ncp->nciop);
792}
793
794#ifdef LOCKNUMREC
795static int
796NC_init_pe(NC *ncp, int basepe) {
797        if (basepe < 0 || basepe >= _num_pes()) {
798                return NC_EINVAL; /* invalid base pe */
799        }
800        /* initialize common values */
801        ncp->lock[LOCKNUMREC_VALUE] = 0;
802        ncp->lock[LOCKNUMREC_LOCK] = 0;
803        ncp->lock[LOCKNUMREC_SERVING] = 0;
804        ncp->lock[LOCKNUMREC_BASEPE] =  basepe;
805        return NC_NOERR;
806}
807#endif
808
809
810/*
811 * Compute the expected size of the file.
812 */
813int
814NC_calcsize(const NC *ncp, off_t *calcsizep)
815{
816        NC_var **vpp = (NC_var **)ncp->vars.value;
817        NC_var *const *const end = &vpp[ncp->vars.nelems];
818        NC_var *last_fix = NULL;        /* last "non-record" var */
819        int numrecvars = 0;     /* number of record variables */
820
821        if(ncp->vars.nelems == 0) { /* no non-record variables and
822                                       no record variables */
823            *calcsizep = ncp->xsz; /* size of header */
824            return NC_NOERR;
825        }
826
827        for( /*NADA*/; vpp < end; vpp++) {
828            if(IS_RECVAR(*vpp)) {
829                numrecvars++;
830            } else {
831                last_fix = *vpp;
832            }
833        }
834
835        if(numrecvars == 0) {
836            off_t varsize;
837            assert(last_fix != NULL);
838            varsize = last_fix->len;
839            if(last_fix->len == X_UINT_MAX) { /* huge last fixed var */
840                int i;
841                varsize = 1;
842                    for(i = 0; i < last_fix->ndims; i++ ) {
843                        varsize *= last_fix->shape[i];
844                    }
845            }
846            *calcsizep = last_fix->begin + varsize;
847            /*last_var = last_fix;*/
848        } else {       /* we have at least one record variable */
849            *calcsizep = ncp->begin_rec + ncp->numrecs * ncp->recsize;
850        }
851
852        return NC_NOERR;
853}
854
855/* Public */
856
857int NC3_new_nc(NC** ncpp)
858{
859        NC *ncp;
860
861#if _CRAYMPP && defined(LOCKNUMREC)
862        ncp = (NC *) shmalloc(sizeof(NC));
863#else
864        ncp = (NC *) malloc(sizeof(NC));
865#endif /* _CRAYMPP && LOCKNUMREC */
866        if(ncp == NULL)
867                return NC_ENOMEM;
868        (void) memset(ncp, 0, sizeof(NC));
869
870        ncp->xsz = MIN_NC_XSZ;
871        assert(ncp->xsz == ncx_len_NC(ncp,0));
872       
873        if(ncpp) *ncpp = ncp;
874        return NC_NOERR;
875
876}
877
878/* WARNING: SIGNATURE CHANGE */
879int
880NC3_create(const char *path, int ioflags,
881                size_t initialsz, int basepe,
882                size_t *chunksizehintp,
883                int use_parallel, void* parameters,
884                NC_Dispatch* dispatch, NC** ncpp)
885{
886        NC *ncp;
887        int status;
888        void *xp = NULL;
889        int sizeof_off_t = 0;
890
891#if ALWAYS_NC_SHARE /* DEBUG */
892        fSet(ioflags, NC_SHARE);
893#endif
894
895        ncp = new_NC(chunksizehintp,dispatch);
896        if(ncp == NULL)
897                return NC_ENOMEM;
898
899#if defined(LOCKNUMREC) /* && _CRAYMPP */
900        if (status = NC_init_pe(ncp, basepe)) {
901                return status;
902        }
903#else
904        /*
905         * !_CRAYMPP, only pe 0 is valid
906         */
907        if(basepe != 0)
908                return NC_EINVAL;
909#endif
910
911        assert(ncp->flags == 0);
912
913        /* Apply default create format. */
914        if (default_create_format == NC_FORMAT_64BIT)
915          ioflags |= NC_64BIT_OFFSET;
916
917        if (fIsSet(ioflags, NC_64BIT_OFFSET)) {
918          fSet(ncp->flags, NC_64BIT_OFFSET);
919          sizeof_off_t = 8;
920        } else {
921          sizeof_off_t = 4;
922        }
923
924        assert(ncp->xsz == ncx_len_NC(ncp,sizeof_off_t));
925       
926        status =  ncio_create(path, ioflags, initialsz,
927                              0, ncp->xsz, &ncp->chunk,
928                              &ncp->nciop, &xp);
929        if(status != NC_NOERR)
930        {
931                /* translate error status */
932                if(status == EEXIST)
933                        status = NC_EEXIST;
934                goto unwind_alloc;
935        }
936
937        fSet(ncp->flags, NC_CREAT);
938
939        if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
940        {
941                /*
942                 * NC_SHARE implies sync up the number of records as well.
943                 * (File format version one.)
944                 * Note that other header changes are not shared
945                 * automatically.  Some sort of IPC (external to this package)
946                 * would be used to trigger a call to nc_sync().
947                 */
948                fSet(ncp->flags, NC_NSYNC);
949        }
950
951        status = ncx_put_NC(ncp, &xp, sizeof_off_t, ncp->xsz);
952        if(status != NC_NOERR)
953                goto unwind_ioc;
954
955        add_to_NCList(ncp);
956
957        if(chunksizehintp != NULL)
958                *chunksizehintp = ncp->chunk;
959
960        ncp->int_ncid = ncp->nciop->fd;
961
962        if(ncpp) *ncpp = ncp;   
963
964        return NC_NOERR;
965
966unwind_ioc:
967        (void) ncio_close(ncp->nciop, 1); /* N.B.: unlink */
968        ncp->nciop = NULL;
969        /*FALLTHRU*/
970unwind_alloc:
971        free_NC(ncp);
972        return status;
973}
974
975/* This function sets a default create flag that will be logically
976   or'd to whatever flags are passed into nc_create for all future
977   calls to nc_create.
978   Valid default create flags are NC_64BIT_OFFSET, NC_CLOBBER,
979   NC_LOCK, NC_SHARE. */
980int
981nc_set_default_format(int format, int *old_formatp)
982{
983    /* Return existing format if desired. */
984    if (old_formatp)
985      *old_formatp = default_create_format;
986
987    /* Make sure only valid format is set. */
988#ifdef USE_NETCDF4
989    if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT &&
990        format != NC_FORMAT_NETCDF4 && format != NC_FORMAT_NETCDF4_CLASSIC)
991      return NC_EINVAL;
992#else
993    if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT)
994      return NC_EINVAL;
995#endif
996    default_create_format = format;
997    return NC_NOERR;
998}
999
1000int
1001NC3_open(const char * path, int ioflags,
1002               int basepe, size_t *chunksizehintp,
1003               int use_parallel,void* parameters,
1004               NC_Dispatch* dispatch, NC** ncpp)
1005{
1006        NC *ncp;
1007        int status;
1008
1009#if ALWAYS_NC_SHARE /* DEBUG */
1010        fSet(ioflags, NC_SHARE);
1011#endif
1012
1013        ncp = new_NC(chunksizehintp,dispatch);
1014        if(ncp == NULL)
1015                return NC_ENOMEM;
1016
1017#if defined(LOCKNUMREC) /* && _CRAYMPP */
1018        if (status = NC_init_pe(ncp, basepe)) {
1019                return status;
1020        }
1021#else
1022        /*
1023         * !_CRAYMPP, only pe 0 is valid
1024         */
1025        if(basepe != 0)
1026                return NC_EINVAL;
1027#endif
1028
1029        status = ncio_open(path, ioflags, 0, 0, &ncp->chunk, &ncp->nciop, 0);
1030        if(status)
1031                goto unwind_alloc;
1032
1033        assert(ncp->flags == 0);
1034
1035        if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
1036        {
1037                /*
1038                 * NC_SHARE implies sync up the number of records as well.
1039                 * (File format version one.)
1040                 * Note that other header changes are not shared
1041                 * automatically.  Some sort of IPC (external to this package)
1042                 * would be used to trigger a call to nc_sync().
1043                 */
1044                fSet(ncp->flags, NC_NSYNC);
1045        }
1046
1047        status = nc_get_NC(ncp);
1048        if(status != NC_NOERR)
1049                goto unwind_ioc;
1050
1051        add_to_NCList(ncp);
1052
1053        if(chunksizehintp != NULL)
1054                *chunksizehintp = ncp->chunk;
1055
1056        ncp->int_ncid = ncp->nciop->fd;
1057
1058        if(ncpp) *ncpp = ncp;
1059
1060        return NC_NOERR;
1061
1062unwind_ioc:
1063        (void) ncio_close(ncp->nciop, 0);
1064        ncp->nciop = NULL;
1065        /*FALLTHRU*/
1066unwind_alloc:
1067        free_NC(ncp);
1068        return status;
1069}
1070
1071int
1072NC3__enddef(int ncid,
1073        size_t h_minfree, size_t v_align,
1074        size_t v_minfree, size_t r_align)
1075{
1076        int status;
1077        NC *ncp;
1078
1079        status = NC_check_id(ncid, &ncp); 
1080        if(status != NC_NOERR)
1081                return status;
1082
1083        if(!NC_indef(ncp))
1084                return(NC_ENOTINDEFINE);
1085
1086        return (NC_endef(ncp, h_minfree, v_align, v_minfree, r_align));
1087}
1088
1089
1090int
1091NC3_close(int ncid)
1092{
1093        int status = NC_NOERR;
1094        NC *ncp; 
1095
1096        status = NC_check_id(ncid, &ncp); 
1097        if(status != NC_NOERR)
1098                return status;
1099
1100        if(NC_indef(ncp))
1101        {
1102                status = NC_endef(ncp, 0, 1, 0, 1); /* TODO: defaults */
1103                if(status != NC_NOERR )
1104                {
1105                        (void) nc_abort(ncid);
1106                        return status;
1107                }
1108        }
1109        else if(!NC_readonly(ncp))
1110        {
1111                status = NC_sync(ncp);
1112                /* flush buffers before any filesize comparisons */
1113                (void) ncio_sync(ncp->nciop);
1114        }
1115
1116        /*
1117         * If file opened for writing and filesize is less than
1118         * what it should be (due to previous use of NOFILL mode),
1119         * pad it to correct size, as reported by NC_calcsize().
1120         */
1121        if (status == ENOERR) {
1122            off_t filesize;     /* current size of open file */
1123            off_t calcsize;     /* calculated file size, from header */
1124            status = ncio_filesize(ncp->nciop, &filesize);
1125            if(status != ENOERR)
1126                return status;
1127            status = NC_calcsize(ncp, &calcsize);
1128            if(status != NC_NOERR)
1129                return status;
1130            if(filesize < calcsize && !NC_readonly(ncp)) {
1131                status = ncio_pad_length(ncp->nciop, calcsize);
1132                if(status != ENOERR)
1133                    return status;
1134            }
1135        }
1136
1137        (void) ncio_close(ncp->nciop, 0);
1138        ncp->nciop = NULL;
1139
1140        del_from_NCList(ncp);
1141
1142        free_NC(ncp);
1143
1144        return status;
1145}
1146
1147/*
1148 * In data mode, same as ncclose.
1149 * In define mode, restore previous definition.
1150 * In create, remove the file.
1151 */
1152int
1153NC3_abort(int ncid)
1154{
1155        int status;
1156        NC *ncp;
1157        int doUnlink = 0;
1158
1159        status = NC_check_id(ncid, &ncp); 
1160        if(status != NC_NOERR)
1161                return status;
1162
1163        doUnlink = NC_IsNew(ncp);
1164
1165        if(ncp->old != NULL)
1166        {
1167                /* a plain redef, not a create */
1168                assert(!NC_IsNew(ncp));
1169                assert(fIsSet(ncp->flags, NC_INDEF));
1170                free_NC(ncp->old);
1171                ncp->old = NULL;
1172                fClr(ncp->flags, NC_INDEF);
1173        }
1174        else if(!NC_readonly(ncp))
1175        {
1176                status = NC_sync(ncp);
1177                if(status != NC_NOERR)
1178                        return status;
1179        }
1180
1181
1182        (void) ncio_close(ncp->nciop, doUnlink);
1183        ncp->nciop = NULL;
1184
1185        del_from_NCList(ncp);
1186
1187        free_NC(ncp);
1188
1189        return NC_NOERR;
1190}
1191
1192
1193int
1194NC3_redef(int ncid)
1195{
1196        int status;
1197        NC *ncp;
1198
1199        status = NC_check_id(ncid, &ncp); 
1200        if(status != NC_NOERR)
1201                return status;
1202
1203        if(NC_readonly(ncp))
1204                return NC_EPERM;
1205
1206        if(NC_indef(ncp))
1207                return NC_EINDEFINE;
1208
1209       
1210        if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
1211        {
1212                /* read in from disk */
1213                status = read_NC(ncp);
1214                if(status != NC_NOERR)
1215                        return status;
1216        }
1217
1218        ncp->old = dup_NC(ncp);
1219        if(ncp->old == NULL)
1220                return NC_ENOMEM;
1221
1222        fSet(ncp->flags, NC_INDEF);
1223
1224        return NC_NOERR;
1225}
1226
1227
1228int
1229NC3_inq(int ncid,
1230        int *ndimsp,
1231        int *nvarsp,
1232        int *nattsp,
1233        int *xtendimp)
1234{
1235        int status;
1236        NC *ncp;
1237
1238        status = NC_check_id(ncid, &ncp); 
1239        if(status != NC_NOERR)
1240                return status;
1241
1242        if(ndimsp != NULL)
1243                *ndimsp = (int) ncp->dims.nelems;
1244        if(nvarsp != NULL)
1245                *nvarsp = (int) ncp->vars.nelems;
1246        if(nattsp != NULL)
1247                *nattsp = (int) ncp->attrs.nelems;
1248        if(xtendimp != NULL)
1249                *xtendimp = find_NC_Udim(&ncp->dims, NULL);
1250
1251        return NC_NOERR;
1252}
1253
1254int 
1255NC3_inq_unlimdim(int ncid, int *xtendimp)
1256{
1257        int status;
1258        NC *ncp;
1259
1260        status = NC_check_id(ncid, &ncp); 
1261        if(status != NC_NOERR)
1262                return status;
1263
1264        if(xtendimp != NULL)
1265                *xtendimp = find_NC_Udim(&ncp->dims, NULL);
1266
1267        return NC_NOERR;
1268}
1269
1270int
1271NC3_sync(int ncid)
1272{
1273        int status;
1274        NC *ncp;
1275
1276        status = NC_check_id(ncid, &ncp); 
1277        if(status != NC_NOERR)
1278                return status;
1279
1280        if(NC_indef(ncp))
1281                return NC_EINDEFINE;
1282
1283        if(NC_readonly(ncp))
1284        {
1285                return read_NC(ncp);
1286        }
1287        /* else, read/write */
1288
1289        status = NC_sync(ncp);
1290        if(status != NC_NOERR)
1291                return status;
1292
1293        status = ncio_sync(ncp->nciop);
1294        if(status != NC_NOERR)
1295                return status;
1296
1297#ifdef USE_FSYNC
1298        /* may improve concurrent access, but slows performance if
1299         * called frequently */
1300#ifndef WIN32
1301        status = fsync(ncp->nciop->fd);
1302#else
1303        status = _commit(ncp->nciop->fd);
1304#endif  /* WIN32 */
1305#endif  /* USE_FSYNC */
1306
1307        return status;
1308}
1309
1310
1311int
1312NC3_set_fill(int ncid,
1313        int fillmode, int *old_mode_ptr)
1314{
1315        int status;
1316        NC *ncp;
1317        int oldmode;
1318
1319        status = NC_check_id(ncid, &ncp); 
1320        if(status != NC_NOERR)
1321                return status;
1322
1323        if(NC_readonly(ncp))
1324                return NC_EPERM;
1325
1326        oldmode = fIsSet(ncp->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL;
1327
1328        if(fillmode == NC_NOFILL)
1329        {
1330                fSet(ncp->flags, NC_NOFILL);
1331        }
1332        else if(fillmode == NC_FILL)
1333        {
1334                if(fIsSet(ncp->flags, NC_NOFILL))
1335                {
1336                        /*
1337                         * We are changing back to fill mode
1338                         * so do a sync
1339                         */
1340                        status = NC_sync(ncp);
1341                        if(status != NC_NOERR)
1342                                return status;
1343                }
1344                fClr(ncp->flags, NC_NOFILL);
1345        }
1346        else
1347        {
1348                return NC_EINVAL; /* Invalid fillmode */
1349        }
1350
1351        if(old_mode_ptr != NULL)
1352                *old_mode_ptr = oldmode;
1353
1354        return NC_NOERR;
1355}
1356
1357#ifdef LOCKNUMREC
1358
1359/* create function versions of the NC_*_numrecs macros */
1360size_t
1361NC_get_numrecs(const NC *ncp) {
1362        shmem_t numrec;
1363        shmem_short_get(&numrec, (shmem_t *) ncp->lock + LOCKNUMREC_VALUE, 1,
1364                ncp->lock[LOCKNUMREC_BASEPE]);
1365        return (size_t) numrec;
1366}
1367
1368void
1369NC_set_numrecs(NC *ncp, size_t nrecs)
1370{
1371    shmem_t numrec = (shmem_t) nrecs;
1372    /* update local value too */
1373    ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrec;
1374    shmem_short_put((shmem_t *) ncp->lock + LOCKNUMREC_VALUE, &numrec, 1,
1375    ncp->lock[LOCKNUMREC_BASEPE]);
1376}
1377
1378void NC_increase_numrecs(NC *ncp, size_t nrecs)
1379{
1380    /* this is only called in one place that's already protected
1381     * by a lock ... so don't worry about it */
1382    if (nrecs > NC_get_numrecs(ncp))
1383        NC_set_numrecs(ncp, nrecs);
1384}
1385
1386#endif /* LOCKNUMREC */
1387
1388/* everyone in communicator group will be executing this */
1389/*ARGSUSED*/
1390int
1391NC3_set_base_pe(int ncid, int pe)
1392{
1393#if _CRAYMPP && defined(LOCKNUMREC)
1394        int status;
1395        NC *ncp;
1396        shmem_t numrecs;
1397
1398        if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
1399                return status;
1400        }
1401        if (pe < 0 || pe >= _num_pes()) {
1402                return NC_EINVAL; /* invalid base pe */
1403        }
1404
1405        numrecs = (shmem_t) NC_get_numrecs(ncp);
1406
1407        ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrecs;
1408
1409        /* update serving & lock values for a "smooth" transition */
1410        /* note that the "real" server will being doing this as well */
1411        /* as all the rest in the group */
1412        /* must have syncronization before & after this step */
1413        shmem_short_get(
1414                (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
1415                (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
1416                1, ncp->lock[LOCKNUMREC_BASEPE]);
1417
1418        shmem_short_get(
1419                (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
1420                (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
1421                1, ncp->lock[LOCKNUMREC_BASEPE]);
1422
1423        /* complete transition */
1424        ncp->lock[LOCKNUMREC_BASEPE] = (ushmem_t) pe;
1425
1426#endif /* _CRAYMPP && LOCKNUMREC */
1427        return NC_NOERR;
1428}
1429
1430/*ARGSUSED*/
1431int
1432NC3_inq_base_pe(int ncid, int *pe)
1433{
1434#if _CRAYMPP && defined(LOCKNUMREC)
1435        int status;
1436        NC *ncp;
1437
1438        if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
1439                return status;
1440        }
1441
1442        *pe = (int) ncp->lock[LOCKNUMREC_BASEPE];
1443#else
1444        /*
1445         * !_CRAYMPP, only pe 0 is valid
1446         */
1447        *pe = 0;
1448#endif /* _CRAYMPP && LOCKNUMREC */
1449        return NC_NOERR;
1450}
1451
1452int
1453NC3_inq_format(int ncid, int *formatp)
1454{
1455        int status;
1456        NC *ncp;
1457
1458        status = NC_check_id(ncid, &ncp); 
1459        if(status != NC_NOERR)
1460                return status;
1461
1462        /* only need to check for netCDF-3 variants, since this is never called for netCDF-4
1463           files */
1464        *formatp = fIsSet(ncp->flags, NC_64BIT_OFFSET) ? NC_FORMAT_64BIT
1465            : NC_FORMAT_CLASSIC; 
1466        return NC_NOERR;
1467}
1468
1469/* The sizes of types may vary from platform to platform, but within
1470 * netCDF files, type sizes are fixed. */
1471#define NC_BYTE_LEN 1
1472#define NC_CHAR_LEN 1
1473#define NC_SHORT_LEN 2
1474#define NC_INT_LEN 4
1475#define NC_FLOAT_LEN 4
1476#define NC_DOUBLE_LEN 8
1477#define NUM_ATOMIC_TYPES 6
1478
1479/* This netCDF-4 function proved so popular that a netCDF-classic
1480 * version is provided. You're welcome. */
1481int
1482NC3_inq_type(int ncid, nc_type typeid, char *name, size_t *size)
1483{
1484   int atomic_size[NUM_ATOMIC_TYPES] = {NC_BYTE_LEN, NC_CHAR_LEN, NC_SHORT_LEN, 
1485                                        NC_INT_LEN, NC_FLOAT_LEN, NC_DOUBLE_LEN};
1486   char atomic_name[NUM_ATOMIC_TYPES][NC_MAX_NAME + 1] = {"byte", "char", "short", 
1487                                                          "int", "float", "double"};
1488   
1489   /* Only netCDF classic model needs to be handled. */
1490   if (typeid < NC_BYTE || typeid > NC_DOUBLE)
1491      return NC_EBADTYPE;
1492
1493   /* Give the user the values they want. Subtract one because types
1494    * are numbered starting at 1, not 0. */
1495   if (name)
1496      strcpy(name, atomic_name[typeid - 1]);
1497   if (size)
1498      *size = atomic_size[typeid - 1];
1499
1500   return NC_NOERR;
1501}
1502
1503int
1504nc_delete_mp(const char * path, int basepe)
1505{
1506        NC *ncp;
1507        int status;
1508        size_t chunk = 512;
1509
1510        status = NC3_new_nc(&ncp);
1511        if(status) return status;
1512        ncp->chunk = chunk;
1513       
1514#if defined(LOCKNUMREC) /* && _CRAYMPP */
1515        if (status = NC_init_pe(ncp, basepe)) {
1516                return status;
1517        }
1518#else
1519        /*
1520         * !_CRAYMPP, only pe 0 is valid
1521         */
1522        if(basepe != 0)
1523                return NC_EINVAL;
1524#endif
1525
1526        status = ncio_open(path, NC_NOWRITE,
1527                0, 0, &ncp->chunk,
1528                &ncp->nciop, 0);
1529        if(status)
1530                goto unwind_alloc;
1531
1532        assert(ncp->flags == 0);
1533
1534        status = nc_get_NC(ncp);
1535        if(status != NC_NOERR)
1536        {
1537                /* Not a netcdf file, don't delete */
1538                /* ??? is this the right semantic? what if it was just too big? */
1539                (void) ncio_close(ncp->nciop, 0);
1540        }
1541        else
1542        {
1543                /* ncio_close does the unlink */
1544                status = ncio_close(ncp->nciop, 1); /* ncio_close does the unlink */
1545        }
1546        ncp->nciop = NULL;
1547
1548        ncp->nciop = NULL;
1549unwind_alloc:
1550        free_NC(ncp);
1551        return status;
1552}
1553
1554int
1555nc_delete(const char * path)
1556{
1557        return nc_delete_mp(path, 0);
1558}
1559
Note: See TracBrowser for help on using the repository browser.