ncdf4a13/libsrc/nc.c

Go to the documentation of this file.
00001 /*
00002  *      Copyright 1996, University Corporation for Atmospheric Research
00003  *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
00004  */
00005 /* $Id: nc.c,v 2.143 2006/01/28 20:01:19 ed Exp $ */
00006 
00007 #include "nc.h"
00008 #include "rnd.h"
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <assert.h>
00012 #include "ncx.h"
00013 #if defined(LOCKNUMREC) /* && _CRAYMPP */
00014 #  include <mpp/shmem.h>
00015 #  include <intrinsics.h>
00016 #endif
00017 
00018 /* list of open netcdf's */
00019 static NC *NClist = NULL;
00020 
00021 /* This is the default create format for nc_create and nc__create. */
00022 int default_create_format = NC_FORMAT_CLASSIC;
00023 
00024 /* These have to do with version numbers. */
00025 #define MAGIC_NUM_LEN 4
00026 #define VER_CLASSIC 1
00027 #define VER_64BIT_OFFSET 2
00028 #define VER_HDF5 3
00029 
00030 static void
00031 add_to_NCList(NC *ncp)
00032 {
00033         assert(ncp != NULL);
00034 
00035         ncp->prev = NULL;
00036         if(NClist != NULL)
00037                 NClist->prev = ncp;
00038         ncp->next = NClist;
00039         NClist = ncp;
00040 }
00041 
00042 static void
00043 del_from_NCList(NC *ncp)
00044 {
00045         assert(ncp != NULL);
00046 
00047         if(NClist == ncp)
00048         {
00049                 assert(ncp->prev == NULL);
00050                 NClist = ncp->next;
00051         }
00052         else
00053         {
00054                 assert(ncp->prev != NULL);
00055                 ncp->prev->next = ncp->next;
00056         }
00057 
00058         if(ncp->next != NULL)
00059                 ncp->next->prev = ncp->prev;
00060 
00061         ncp->next = NULL;
00062         ncp->prev = NULL;
00063 }
00064 
00065 
00066 int
00067 NC_check_id(int ncid, NC **ncpp)
00068 {
00069         NC *ncp;
00070 
00071         if(ncid >= 0)
00072         {
00073                 for(ncp = NClist; ncp != NULL; ncp = ncp->next)
00074                 {
00075                         if(ncp->nciop->fd == ncid)
00076                         {
00077                                 *ncpp = ncp;
00078                                 return NC_NOERR; /* normal return */
00079                         }
00080                 }
00081         }
00082 
00083         /* else, not found */
00084         return NC_EBADID;
00085 }
00086 
00087 
00088 static void
00089 free_NC(NC *ncp)
00090 {
00091         if(ncp == NULL)
00092                 return;
00093         free_NC_dimarrayV(&ncp->dims);
00094         free_NC_attrarrayV(&ncp->attrs);
00095         free_NC_vararrayV(&ncp->vars);
00096 #if _CRAYMPP && defined(LOCKNUMREC)
00097         shfree(ncp);
00098 #else
00099         free(ncp);
00100 #endif /* _CRAYMPP && LOCKNUMREC */
00101 }
00102 
00103 
00104 static NC *
00105 new_NC(const size_t *chunkp)
00106 {
00107         NC *ncp;
00108 
00109 #if _CRAYMPP && defined(LOCKNUMREC)
00110         ncp = (NC *) shmalloc(sizeof(NC));
00111 #else
00112         ncp = (NC *) malloc(sizeof(NC));
00113 #endif /* _CRAYMPP && LOCKNUMREC */
00114         if(ncp == NULL)
00115                 return NULL;
00116         (void) memset(ncp, 0, sizeof(NC));
00117 
00118         ncp->xsz = MIN_NC_XSZ;
00119         assert(ncp->xsz == ncx_len_NC(ncp,0));
00120         
00121         ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT;
00122 
00123         return ncp;
00124 }
00125 
00126 
00127 static NC *
00128 dup_NC(const NC *ref)
00129 {
00130         NC *ncp;
00131 
00132 #if _CRAYMPP && defined(LOCKNUMREC)
00133         ncp = (NC *) shmalloc(sizeof(NC));
00134 #else
00135         ncp = (NC *) malloc(sizeof(NC));
00136 #endif /* _CRAYMPP && LOCKNUMREC */
00137         if(ncp == NULL)
00138                 return NULL;
00139         (void) memset(ncp, 0, sizeof(NC));
00140 
00141         if(dup_NC_dimarrayV(&ncp->dims, &ref->dims) != NC_NOERR)
00142                 goto err;
00143         if(dup_NC_attrarrayV(&ncp->attrs, &ref->attrs) != NC_NOERR)
00144                 goto err;
00145         if(dup_NC_vararrayV(&ncp->vars, &ref->vars) != NC_NOERR)
00146                 goto err;
00147 
00148         ncp->xsz = ref->xsz;
00149         ncp->begin_var = ref->begin_var;
00150         ncp->begin_rec = ref->begin_rec;
00151         ncp->recsize = ref->recsize;
00152         NC_set_numrecs(ncp, NC_get_numrecs(ref));
00153         return ncp;
00154 err:
00155         free_NC(ncp);
00156         return NULL;
00157 }
00158 
00159 
00160 /*
00161  *  Verify that this is a user nc_type
00162  * Formerly
00163 NCcktype()
00164  * Sense of the return is changed.
00165  */
00166 int
00167 nc_cktype(nc_type type)
00168 {
00169         switch((int)type){
00170         case NC_BYTE:
00171         case NC_CHAR:
00172         case NC_SHORT:
00173         case NC_INT:
00174         case NC_FLOAT:
00175         case NC_DOUBLE:
00176                 return(NC_NOERR);
00177         }
00178         return(NC_EBADTYPE);
00179 }
00180 
00181 
00182 /*
00183  * How many objects of 'type'
00184  * will fit into xbufsize?
00185  */
00186 size_t
00187 ncx_howmany(nc_type type, size_t xbufsize)
00188 {
00189         switch(type){
00190         case NC_BYTE:
00191         case NC_CHAR:
00192                 return xbufsize;
00193         case NC_SHORT:
00194                 return xbufsize/X_SIZEOF_SHORT;
00195         case NC_INT:
00196                 return xbufsize/X_SIZEOF_INT;
00197         case NC_FLOAT:
00198                 return xbufsize/X_SIZEOF_FLOAT;
00199         case NC_DOUBLE:
00200                 return xbufsize/X_SIZEOF_DOUBLE;
00201         }
00202         assert("ncx_howmany: Bad type" == 0);
00203         return(0);
00204 }
00205 
00206 #define D_RNDUP(x, align) _RNDUP(x, (off_t)(align))
00207 
00208 /*
00209  * Compute each variable's 'begin' offset,
00210  * update 'begin_rec' as well.
00211  */
00212 static int
00213 NC_begins(NC *ncp,
00214         size_t h_minfree, size_t v_align,
00215         size_t v_minfree, size_t r_align)
00216 {
00217         size_t ii;
00218         int sizeof_off_t;
00219         off_t index = 0;
00220         NC_var **vpp;
00221         NC_var *last = NULL;
00222 
00223         if(v_align == NC_ALIGN_CHUNK)
00224                 v_align = ncp->chunk;
00225         if(r_align == NC_ALIGN_CHUNK)
00226                 r_align = ncp->chunk;
00227 
00228         if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) {
00229           sizeof_off_t = 8;
00230         } else {
00231           sizeof_off_t = 4;
00232         }
00233         
00234         ncp->xsz = ncx_len_NC(ncp,sizeof_off_t);
00235 
00236         if(ncp->vars.nelems == 0) 
00237                 return NC_NOERR;
00238 
00239         /* only (re)calculate begin_var if there is not sufficient space in header
00240            or start of non-record variables is not aligned as requested by valign */
00241         if (ncp->begin_var < ncp->xsz + h_minfree ||
00242             ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) ) 
00243         {
00244           index = (off_t) ncp->xsz;
00245           ncp->begin_var = D_RNDUP(index, v_align);
00246           if(ncp->begin_var < index + h_minfree)
00247           {
00248             ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align);
00249           }
00250         }
00251         index = ncp->begin_var;
00252 
00253         /* loop thru vars, first pass is for the 'non-record' vars */
00254         vpp = ncp->vars.value;
00255         for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++)
00256         {
00257                 if( IS_RECVAR(*vpp) )
00258                 {
00259                         /* skip record variables on this pass */
00260                         continue;
00261                 }
00262 #if 0
00263 fprintf(stderr, "    VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
00264 #endif
00265                 if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) ) 
00266                 {
00267                     return NC_EVARSIZE;
00268                 }
00269                 (*vpp)->begin = index;
00270                 index += (*vpp)->len;
00271         }
00272 
00273         /* only (re)calculate begin_rec if there is not sufficient
00274            space at end of non-record variables or if start of record
00275            variables is not aligned as requested by r_align */
00276         if (ncp->begin_rec < index + v_minfree ||
00277             ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) )
00278         {
00279           ncp->begin_rec = D_RNDUP(index, r_align);
00280           if(ncp->begin_rec < index + v_minfree)
00281           {
00282             ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align);
00283           }
00284         }
00285         index = ncp->begin_rec;
00286 
00287         ncp->recsize = 0;
00288 
00289         /* loop thru vars, second pass is for the 'record' vars */
00290         vpp = (NC_var **)ncp->vars.value;
00291         for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++)
00292         {
00293                 if( !IS_RECVAR(*vpp) )
00294                 {
00295                         /* skip non-record variables on this pass */
00296                         continue;
00297                 }
00298 
00299 #if 0
00300 fprintf(stderr, "    REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
00301 #endif
00302                 if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) ) 
00303                 {
00304                     return NC_EVARSIZE;
00305                 }
00306                 (*vpp)->begin = index;
00307                 index += (*vpp)->len;
00308                 /* check if record size must fit in 32-bits */
00309 #if SIZEOF_OFF_T == SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4
00310                 if( ncp->recsize > X_UINT_MAX - (*vpp)->len )
00311                 {
00312                     return NC_EVARSIZE;
00313                 }
00314 #endif
00315                 ncp->recsize += (*vpp)->len;
00316                 last = (*vpp);
00317         }
00318 
00319         /*
00320          * for special case of exactly one record variable, pack value
00321          */
00322         if(last != NULL && ncp->recsize == last->len)
00323                 ncp->recsize = *last->dsizes * last->xsz;
00324 
00325         if(NC_IsNew(ncp))
00326                 NC_set_numrecs(ncp, 0);
00327         return NC_NOERR;
00328 }
00329 
00330 
00331 /*
00332  * Read just the numrecs member.
00333  * (A relatively expensive way to do things.)
00334  */
00335 int
00336 read_numrecs(NC *ncp)
00337 {
00338         int status = NC_NOERR;
00339         const void *xp = NULL;
00340         size_t nrecs = NC_get_numrecs(ncp);
00341 
00342         assert(!NC_indef(ncp));
00343 
00344 #define NC_NUMRECS_OFFSET 4
00345 #define NC_NUMRECS_EXTENT 4
00346         status = ncp->nciop->get(ncp->nciop,
00347                  NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, 0, (void **)&xp);
00348                                         /* cast away const */
00349         if(status != NC_NOERR)
00350                 return status;
00351 
00352         status = ncx_get_size_t(&xp, &nrecs);
00353 
00354         (void) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, 0);
00355 
00356         if(status == NC_NOERR)
00357         {
00358                 NC_set_numrecs(ncp, nrecs);
00359                 fClr(ncp->flags, NC_NDIRTY);
00360         }
00361 
00362         return status;
00363 }
00364 
00365 
00366 /*
00367  * Write out just the numrecs member.
00368  * (A relatively expensive way to do things.)
00369  */
00370 int
00371 write_numrecs(NC *ncp)
00372 {
00373         int status = NC_NOERR;
00374         void *xp = NULL;
00375 
00376         assert(!NC_readonly(ncp));
00377         assert(!NC_indef(ncp));
00378 
00379         status = ncp->nciop->get(ncp->nciop,
00380                  NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, RGN_WRITE, &xp);
00381         if(status != NC_NOERR)
00382                 return status;
00383 
00384         {
00385                 const size_t nrecs = NC_get_numrecs(ncp);
00386                 status = ncx_put_size_t(&xp, &nrecs);
00387         }
00388 
00389         (void) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, RGN_MODIFIED);
00390 
00391         if(status == NC_NOERR)
00392                 fClr(ncp->flags, NC_NDIRTY);
00393 
00394         return status;
00395 }
00396 
00397 
00398 /*
00399  * Read in the header
00400  * It is expensive.
00401  */
00402 static int
00403 read_NC(NC *ncp)
00404 {
00405         int status = NC_NOERR;
00406 
00407         free_NC_dimarrayV(&ncp->dims);
00408         free_NC_attrarrayV(&ncp->attrs);
00409         free_NC_vararrayV(&ncp->vars);
00410 
00411         status = nc_get_NC(ncp);
00412 
00413         if(status == NC_NOERR)
00414                 fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
00415 
00416         return status;
00417 }
00418 
00419 
00420 /*
00421  * Write out the header
00422  */
00423 static int
00424 write_NC(NC *ncp)
00425 {
00426         int status = NC_NOERR;
00427 
00428         assert(!NC_readonly(ncp));
00429 
00430         status = ncx_put_NC(ncp, NULL, 0, 0);
00431 
00432         if(status == NC_NOERR)
00433                 fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
00434 
00435         return status;
00436 }
00437 
00438 
00439 /*
00440  * Write the header or the numrecs if necessary.
00441  */
00442 int
00443 NC_sync(NC *ncp)
00444 {
00445         assert(!NC_readonly(ncp));
00446 
00447         if(NC_hdirty(ncp))
00448         {
00449                 return write_NC(ncp);
00450         }
00451         /* else */
00452 
00453         if(NC_ndirty(ncp))
00454         {
00455                 return write_numrecs(ncp);
00456         }
00457         /* else */
00458 
00459         return NC_NOERR;
00460 }
00461 
00462 
00463 /*
00464  * Initialize the 'non-record' variables.
00465  */
00466 static int
00467 fillerup(NC *ncp)
00468 {
00469         int status = NC_NOERR;
00470         size_t ii;
00471         NC_var **varpp;
00472 
00473         assert(!NC_readonly(ncp));
00474         assert(NC_dofill(ncp));
00475 
00476         /* loop thru vars */
00477         varpp = ncp->vars.value;
00478         for(ii = 0; ii < ncp->vars.nelems; ii++, varpp++)
00479         {
00480                 if(IS_RECVAR(*varpp))
00481                 {
00482                         /* skip record variables */
00483                         continue;
00484                 }
00485 
00486                 status = fill_NC_var(ncp, *varpp, 0);
00487                 if(status != NC_NOERR)
00488                         break;
00489         }
00490         return status;
00491 }
00492 
00493 /* Begin endef */
00494 
00495 /*
00496  */
00497 static int
00498 fill_added_recs(NC *gnu, NC *old)
00499 {
00500         NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
00501 
00502         const int old_nrecs = (int) NC_get_numrecs(old);
00503         int recno = 0;
00504         for(; recno < old_nrecs; recno++)
00505         {
00506                 int varid = (int)old->vars.nelems;
00507                 for(; varid < (int)gnu->vars.nelems; varid++)
00508                 {
00509                         const NC_var *const gnu_varp = *(gnu_varpp + varid);
00510                         if(!IS_RECVAR(gnu_varp))
00511                         {
00512                                 /* skip non-record variables */
00513                                 continue;
00514                         }
00515                         /* else */
00516                         {
00517                         const int status = fill_NC_var(gnu, gnu_varp, recno);
00518                         if(status != NC_NOERR)
00519                                 return status;
00520                         }
00521                 }
00522         }
00523 
00524         return NC_NOERR;
00525 }
00526 
00527 /*
00528  */
00529 static int
00530 fill_added(NC *gnu, NC *old)
00531 {
00532         NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
00533         int varid = (int)old->vars.nelems;
00534 
00535         for(; varid < (int)gnu->vars.nelems; varid++)
00536         {
00537                 const NC_var *const gnu_varp = *(gnu_varpp + varid);
00538                 if(IS_RECVAR(gnu_varp))
00539                 {
00540                         /* skip record variables */
00541                         continue;
00542                 }
00543                 /* else */
00544                 {
00545                 const int status = fill_NC_var(gnu, gnu_varp, 0);
00546                 if(status != NC_NOERR)
00547                         return status;
00548                 }
00549         }
00550 
00551         return NC_NOERR;
00552 }
00553 
00554 
00555 /*
00556  * Move the records "out". 
00557  * Fill as needed.
00558  */
00559 static int
00560 move_recs_r(NC *gnu, NC *old)
00561 {
00562         int status;
00563         int recno;
00564         int varid;
00565         NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
00566         NC_var **old_varpp = (NC_var **)old->vars.value;
00567         NC_var *gnu_varp;
00568         NC_var *old_varp;
00569         off_t gnu_off;
00570         off_t old_off;
00571         const size_t old_nrecs = NC_get_numrecs(old);
00572         
00573         /* Don't parallelize this loop */
00574         for(recno = (int)old_nrecs -1; recno >= 0; recno--)
00575         {
00576         /* Don't parallelize this loop */
00577         for(varid = (int)old->vars.nelems -1; varid >= 0; varid--)
00578         {
00579                 gnu_varp = *(gnu_varpp + varid);
00580                 if(!IS_RECVAR(gnu_varp))
00581                 {
00582                         /* skip non-record variables on this pass */
00583                         continue;
00584                 }
00585                 /* else */
00586 
00587                 /* else, a pre-existing variable */
00588                 old_varp = *(old_varpp + varid);
00589                 gnu_off = gnu_varp->begin + (off_t)(gnu->recsize * recno);
00590                 old_off = old_varp->begin + (off_t)(old->recsize * recno);
00591 
00592                 if(gnu_off == old_off)
00593                         continue;       /* nothing to do */
00594 
00595                 assert(gnu_off > old_off);
00596         
00597                 status = gnu->nciop->move(gnu->nciop, gnu_off, old_off,
00598                          old_varp->len, 0);
00599 
00600                 if(status != NC_NOERR)
00601                         return status;
00602                 
00603         }
00604         }
00605 
00606         NC_set_numrecs(gnu, old_nrecs);
00607 
00608         return NC_NOERR;
00609 }
00610 
00611 
00612 /*
00613  * Move the "non record" variables "out". 
00614  * Fill as needed.
00615  */
00616 static int
00617 move_vars_r(NC *gnu, NC *old)
00618 {
00619         int status;
00620         int varid;
00621         NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
00622         NC_var **old_varpp = (NC_var **)old->vars.value;
00623         NC_var *gnu_varp;
00624         NC_var *old_varp;
00625         off_t gnu_off;
00626         off_t old_off;
00627         
00628         /* Don't parallelize this loop */
00629         for(varid = (int)old->vars.nelems -1;
00630                  varid >= 0; varid--)
00631         {
00632                 gnu_varp = *(gnu_varpp + varid);
00633                 if(IS_RECVAR(gnu_varp))
00634                 {
00635                         /* skip record variables on this pass */
00636                         continue;
00637                 }
00638                 /* else */
00639 
00640                 old_varp = *(old_varpp + varid);
00641                 gnu_off = gnu_varp->begin;
00642                 old_off = old_varp->begin;
00643         
00644                 if(gnu_off == old_off)
00645                         continue;       /* nothing to do */
00646 
00647                 assert(gnu_off > old_off);
00648 
00649                 status = gnu->nciop->move(gnu->nciop, gnu_off, old_off,
00650                          old_varp->len, 0);
00651 
00652                 if(status != NC_NOERR)
00653                         return status;
00654                 
00655         }
00656 
00657         return NC_NOERR;
00658 }
00659 
00660 
00661 /*
00662  * Given a valid ncp, return NC_EVARSIZE if any variable has a bad len 
00663  * (product of non-rec dim sizes too large), else return NC_NOERR.
00664  */
00665 static int
00666 NC_check_vlens(NC *ncp)
00667 {
00668     NC_var **vpp;
00669     /* maximum permitted variable size (or size of one record's worth
00670        of a record variable) in bytes.  This is different for format 1
00671        and format 2. */
00672     size_t vlen_max;
00673     size_t ii;
00674     size_t large_vars_count;
00675     size_t rec_vars_count;
00676     int last;
00677 
00678     if(ncp->vars.nelems == 0) 
00679         return NC_NOERR;
00680 
00681     if ((ncp->flags & NC_64BIT_OFFSET) && sizeof(off_t) > 4) {
00682         /* CDF2 format and LFS */
00683         vlen_max = X_UINT_MAX - 3; /* "- 3" handles rounded-up size */
00684     } else {
00685         /* CDF1 format */
00686         vlen_max = X_INT_MAX - 3;
00687     }
00688     /* Loop through vars, first pass is for non-record variables.   */
00689     large_vars_count = 0;
00690     rec_vars_count = 0;
00691     vpp = ncp->vars.value;
00692     for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
00693         if( !IS_RECVAR(*vpp) ) {
00694             last = 0;
00695             if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
00696                 large_vars_count++;
00697                 last = 1;
00698             }
00699         } else {
00700           rec_vars_count++;
00701         }
00702     }
00703     /* OK if last non-record variable size too large, since not used to 
00704        compute an offset */
00705     if( large_vars_count > 1) { /* only one "too-large" variable allowed */
00706       return NC_EVARSIZE;
00707     }
00708     /* and it has to be the last one */ 
00709     if( large_vars_count == 1 && last == 0) { 
00710       return NC_EVARSIZE;
00711     }
00712     if( rec_vars_count > 0 ) {
00713         /* and if it's the last one, there can't be any record variables */
00714         if( large_vars_count == 1 && last == 1) {
00715             return NC_EVARSIZE;
00716         }
00717         /* Loop through vars, second pass is for record variables.   */
00718         large_vars_count = 0;
00719         vpp = ncp->vars.value;
00720         for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
00721             if( IS_RECVAR(*vpp) ) {
00722                 last = 0;
00723                 if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
00724                     large_vars_count++;
00725                     last = 1;
00726                 }
00727             }
00728         }
00729         /* OK if last record variable size too large, since not used to 
00730            compute an offset */
00731         if( large_vars_count > 1) { /* only one "too-large" variable allowed */
00732             return NC_EVARSIZE;
00733         }
00734         /* and it has to be the last one */ 
00735         if( large_vars_count == 1 && last == 0) { 
00736             return NC_EVARSIZE;
00737         }
00738     }
00739     return NC_NOERR;
00740 }
00741 
00742 
00743 /*
00744  *  End define mode.
00745  *  Common code for ncendef, ncclose(endef)
00746  *  Flushes I/O buffers.
00747  */
00748 static int
00749 NC_endef(NC *ncp,
00750         size_t h_minfree, size_t v_align,
00751         size_t v_minfree, size_t r_align)
00752 {
00753         int status = NC_NOERR;
00754 
00755         assert(!NC_readonly(ncp));
00756         assert(NC_indef(ncp));
00757 
00758         status = NC_check_vlens(ncp);
00759         if(status != NC_NOERR)
00760             return status;
00761         status = NC_begins(ncp, h_minfree, v_align, v_minfree, r_align);
00762         if(status != NC_NOERR)
00763             return status;
00764 
00765         if(ncp->old != NULL)
00766         {
00767                 /* a plain redef, not a create */
00768                 assert(!NC_IsNew(ncp));
00769                 assert(fIsSet(ncp->flags, NC_INDEF));
00770                 assert(ncp->begin_rec >= ncp->old->begin_rec);
00771                 assert(ncp->begin_var >= ncp->old->begin_var);
00772 
00773                 if(ncp->vars.nelems != 0)
00774                 {
00775                 if(ncp->begin_rec > ncp->old->begin_rec)
00776                 {
00777                         status = move_recs_r(ncp, ncp->old);
00778                         if(status != NC_NOERR)
00779                                 return status;
00780                         if(ncp->begin_var > ncp->old->begin_var)
00781                         {
00782                                 status = move_vars_r(ncp, ncp->old);
00783                                 if(status != NC_NOERR)
00784                                         return status;
00785                         } 
00786                         /* else if (ncp->begin_var == ncp->old->begin_var) { NOOP } */
00787                 }
00788                 else
00789                 {       /* Even if (ncp->begin_rec == ncp->old->begin_rec)
00790                            and     (ncp->begin_var == ncp->old->begin_var)
00791                            might still have added a new record variable */
00792                         if(ncp->recsize > ncp->old->recsize)
00793                         {
00794                                 status = move_recs_r(ncp, ncp->old);
00795                                 if(status != NC_NOERR)
00796                                       return status;
00797                         }
00798                 }
00799                 }
00800         }
00801 
00802         status = write_NC(ncp);
00803         if(status != NC_NOERR)
00804                 return status;
00805 
00806         if(NC_dofill(ncp))
00807         {
00808                 if(NC_IsNew(ncp))
00809                 {
00810                         status = fillerup(ncp);
00811                         if(status != NC_NOERR)
00812                                 return status;
00813                         
00814                 }
00815                 else if(ncp->vars.nelems > ncp->old->vars.nelems)
00816                 {
00817                         status = fill_added(ncp, ncp->old);
00818                         if(status != NC_NOERR)
00819                                 return status;
00820                         status = fill_added_recs(ncp, ncp->old);
00821                         if(status != NC_NOERR)
00822                                 return status;
00823                 }
00824         }
00825 
00826         if(ncp->old != NULL)
00827         {
00828                 free_NC(ncp->old);
00829                 ncp->old = NULL;
00830         }
00831 
00832         fClr(ncp->flags, NC_CREAT | NC_INDEF);
00833 
00834         return ncp->nciop->sync(ncp->nciop);
00835 }
00836 
00837 #ifdef LOCKNUMREC
00838 static int
00839 NC_init_pe(NC *ncp, int basepe) {
00840         if (basepe < 0 || basepe >= _num_pes()) {
00841                 return NC_EINVAL; /* invalid base pe */
00842         }
00843         /* initialize common values */
00844         ncp->lock[LOCKNUMREC_VALUE] = 0;
00845         ncp->lock[LOCKNUMREC_LOCK] = 0;
00846         ncp->lock[LOCKNUMREC_SERVING] = 0;
00847         ncp->lock[LOCKNUMREC_BASEPE] =  basepe;
00848         return NC_NOERR;
00849 }
00850 #endif
00851 
00852 
00853 /*
00854  * Compute the expected size of the file.
00855  */
00856 int
00857 NC_calcsize(NC *ncp, off_t *calcsizep)
00858 {
00859         NC_var **vpp = (NC_var **)ncp->vars.value;
00860         NC_var *const *const end = &vpp[ncp->vars.nelems];
00861         NC_var *last_fix = NULL;        /* last "non-record" var */
00862         NC_var *last_rec = NULL;        /* last "record" var */
00863         /*NC_var *last_var;*/
00864         int status;
00865         int numrecvars = 0;     /* number of record variables */
00866 
00867         if(ncp->vars.nelems == 0) { /* no non-record variables and 
00868                                        no record variables */
00869             *calcsizep = ncp->xsz; /* size of header */
00870             return NC_NOERR;
00871         }
00872 
00873         for( /*NADA*/; vpp < end; vpp++) {
00874             status = NC_var_shape(*vpp, &ncp->dims);
00875             if(status != NC_NOERR)
00876                 return status;
00877             if(IS_RECVAR(*vpp)) {
00878                 last_rec = *vpp;
00879                 numrecvars++;
00880             } else {
00881                 last_fix = *vpp;
00882             }
00883         }
00884 
00885         if(numrecvars == 0) {
00886             assert(last_fix != NULL);
00887             *calcsizep = last_fix->begin + last_fix->len;
00888             /*last_var = last_fix;*/
00889         } else {       /* we have at least one record variable */
00890             *calcsizep = ncp->begin_rec + ncp->numrecs * ncp->recsize;
00891             /*last_var = last_rec;*/
00892         }
00893 
00894         return NC_NOERR;
00895 }
00896 
00897 /* Public */
00898 
00899 int
00900 nc__create(const char * path, int ioflags, size_t initialsz,
00901         size_t *chunksizehintp, int *ncid_ptr)
00902 {
00903         return nc__create_mp(path, ioflags, initialsz, 0,
00904                 chunksizehintp, ncid_ptr);
00905 }
00906 
00907 int
00908 nc__create_mp(const char * path, int ioflags, size_t initialsz, int basepe,
00909         size_t *chunksizehintp, int *ncid_ptr)
00910 {
00911         NC *ncp;
00912         int status;
00913         void *xp = NULL;
00914         int sizeof_off_t = 0;
00915 
00916 #if ALWAYS_NC_SHARE /* DEBUG */
00917         fSet(ioflags, NC_SHARE);
00918 #endif
00919 
00920         ncp = new_NC(chunksizehintp);
00921         if(ncp == NULL)
00922                 return NC_ENOMEM;
00923 
00924 #if defined(LOCKNUMREC) /* && _CRAYMPP */
00925         if (status = NC_init_pe(ncp, basepe)) {
00926                 return status;
00927         }
00928 #else
00929         /*
00930          * !_CRAYMPP, only pe 0 is valid
00931          */
00932         if(basepe != 0)
00933                 return NC_EINVAL;
00934 #endif
00935 
00936         assert(ncp->flags == 0);
00937 
00938         /* Apply default create format. */
00939         if (default_create_format == NC_FORMAT_64BIT)
00940           ioflags |= NC_64BIT_OFFSET;
00941 
00942         if (fIsSet(ioflags, NC_64BIT_OFFSET)) {
00943           fSet(ncp->flags, NC_64BIT_OFFSET);
00944           sizeof_off_t = 8;
00945         } else {
00946           sizeof_off_t = 4;
00947         }
00948 
00949         assert(ncp->xsz == ncx_len_NC(ncp,sizeof_off_t));
00950         
00951         status = ncio_create(path, ioflags,
00952                 initialsz,
00953                 0, ncp->xsz, &ncp->chunk,
00954                 &ncp->nciop, &xp);
00955         if(status != NC_NOERR)
00956         {
00957                 /* translate error status */
00958                 if(status == EEXIST)
00959                         status = NC_EEXIST;
00960                 goto unwind_alloc;
00961         }
00962 
00963         fSet(ncp->flags, NC_CREAT);
00964 
00965         if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
00966         {
00967                 /*
00968                  * NC_SHARE implies sync up the number of records as well.
00969                  * (File format version one.)
00970                  * Note that other header changes are not shared
00971                  * automatically.  Some sort of IPC (external to this package)
00972                  * would be used to trigger a call to nc_sync().
00973                  */
00974                 fSet(ncp->flags, NC_NSYNC);
00975         }
00976 
00977         status = ncx_put_NC(ncp, &xp, sizeof_off_t, ncp->xsz);
00978         if(status != NC_NOERR)
00979                 goto unwind_ioc;
00980 
00981         add_to_NCList(ncp);
00982 
00983         if(chunksizehintp != NULL)
00984                 *chunksizehintp = ncp->chunk;
00985         *ncid_ptr = ncp->nciop->fd;
00986         return NC_NOERR;
00987 
00988 unwind_ioc:
00989         (void) ncio_close(ncp->nciop, 1); /* N.B.: unlink */
00990         ncp->nciop = NULL;
00991         /*FALLTHRU*/
00992 unwind_alloc:
00993         free_NC(ncp);
00994         return status;
00995 }
00996 
00997 /* This function sets a default create flag that will be logically
00998    or'd to whatever flags are passed into nc_create for all future
00999    calls to nc_create.
01000    Valid default create flags are NC_64BIT_OFFSET, NC_CLOBBER,
01001    NC_LOCK, NC_SHARE. */
01002 int
01003 nc_set_default_format(int format, int *old_formatp)
01004 {
01005     /* Return existing format if desired. */
01006     if (old_formatp)
01007       *old_formatp = default_create_format;
01008 
01009     /* Make sure only valid format is set. */
01010 #ifdef USE_NETCDF4
01011     if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT &&
01012         format != NC_FORMAT_NETCDF4 && format != NC_FORMAT_NETCDF4_CLASSIC)
01013       return NC_EINVAL;
01014 #else
01015     if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT)
01016       return NC_EINVAL;
01017 #endif
01018     default_create_format = format;
01019     return NC_NOERR;
01020 }
01021 
01022 int
01023 nc_create(const char * path, int ioflags, int *ncid_ptr)
01024 {
01025         return nc__create(path, ioflags, 0, NULL, ncid_ptr);
01026 }
01027 
01028 int
01029 nc__open(const char * path, int ioflags,
01030         size_t *chunksizehintp, int *ncid_ptr)
01031 {
01032         return nc__open_mp(path, ioflags, 0,
01033                 chunksizehintp, ncid_ptr);
01034 }
01035 
01036 int
01037 nc__open_mp(const char * path, int ioflags, int basepe,
01038         size_t *chunksizehintp, int *ncid_ptr)
01039 {
01040         NC *ncp;
01041         int status;
01042 
01043 #if ALWAYS_NC_SHARE /* DEBUG */
01044         fSet(ioflags, NC_SHARE);
01045 #endif
01046 
01047         ncp = new_NC(chunksizehintp);
01048         if(ncp == NULL)
01049                 return NC_ENOMEM;
01050 
01051 #if defined(LOCKNUMREC) /* && _CRAYMPP */
01052         if (status = NC_init_pe(ncp, basepe)) {
01053                 return status;
01054         }
01055 #else
01056         /*
01057          * !_CRAYMPP, only pe 0 is valid
01058          */
01059         if(basepe != 0)
01060                 return NC_EINVAL;
01061 #endif
01062 
01063         status = ncio_open(path, ioflags,
01064                 0, 0, &ncp->chunk,
01065                 &ncp->nciop, 0);
01066         if(status)
01067                 goto unwind_alloc;
01068 
01069         assert(ncp->flags == 0);
01070 
01071         if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
01072         {
01073                 /*
01074                  * NC_SHARE implies sync up the number of records as well.
01075                  * (File format version one.)
01076                  * Note that other header changes are not shared
01077                  * automatically.  Some sort of IPC (external to this package)
01078                  * would be used to trigger a call to nc_sync().
01079                  */
01080                 fSet(ncp->flags, NC_NSYNC);
01081         }
01082 
01083         status = nc_get_NC(ncp);
01084         if(status != NC_NOERR)
01085                 goto unwind_ioc;
01086 
01087         add_to_NCList(ncp);
01088 
01089         if(chunksizehintp != NULL)
01090                 *chunksizehintp = ncp->chunk;
01091         *ncid_ptr = ncp->nciop->fd;
01092         return NC_NOERR;
01093 
01094 unwind_ioc:
01095         (void) ncio_close(ncp->nciop, 0);
01096         ncp->nciop = NULL;
01097         /*FALLTHRU*/
01098 unwind_alloc:
01099         free_NC(ncp);
01100         return status;
01101 }
01102 
01103 int
01104 nc_open(const char * path, int ioflags, int *ncid_ptr)
01105 {
01106         return nc__open(path, ioflags, NULL, ncid_ptr);
01107 }
01108 
01109 
01110 int
01111 nc__enddef(int ncid,
01112         size_t h_minfree, size_t v_align,
01113         size_t v_minfree, size_t r_align)
01114 {
01115         int status;
01116         NC *ncp;
01117 
01118         status = NC_check_id(ncid, &ncp); 
01119         if(status != NC_NOERR)
01120                 return status;
01121 
01122         if(!NC_indef(ncp))
01123                 return(NC_ENOTINDEFINE);
01124 
01125         return (NC_endef(ncp, h_minfree, v_align, v_minfree, r_align));
01126 }
01127 
01128 int
01129 nc_enddef(int ncid)
01130 {
01131         int status;
01132         NC *ncp;
01133 
01134         status = NC_check_id(ncid, &ncp); 
01135         if(status != NC_NOERR)
01136                 return status;
01137 
01138         if(!NC_indef(ncp))
01139                 return(NC_ENOTINDEFINE);
01140 
01141         /* return(NC_endef(ncp, 0, 4096, 0, 4096)); */
01142         return (NC_endef(ncp, 0, 1, 0, 1));
01143 }
01144 
01145 
01146 int
01147 nc_close(int ncid)
01148 {
01149         int status = NC_NOERR;
01150         NC *ncp; 
01151 
01152         status = NC_check_id(ncid, &ncp); 
01153         if(status != NC_NOERR)
01154                 return status;
01155 
01156         if(NC_indef(ncp))
01157         {
01158                 status = NC_endef(ncp, 0, 1, 0, 1); /* TODO: defaults */
01159                 if(status != NC_NOERR )
01160                 {
01161                         (void) nc_abort(ncid);
01162                         return status;
01163                 }
01164         }
01165         else if(!NC_readonly(ncp))
01166         {
01167                 status = NC_sync(ncp);
01168         }
01169 
01170         /* 
01171          * If file opened for writing and file size is different from
01172          * what it should be (due to previous use of NOFILL mode),
01173          * change it to correct size, as reported by NC_calcsize().
01174          */
01175         {
01176             off_t filesize;     /* current size of open file */
01177             off_t calcsize;     /* calculated file size, from header */
01178             status = ncio_filesize(ncp->nciop, &filesize);
01179             if(status != ENOERR)
01180                 return status;
01181             status = NC_calcsize(ncp, &calcsize);
01182             if(status != NC_NOERR)
01183                 return status;
01184             if(filesize < calcsize && !NC_readonly(ncp)) {
01185                 status = ncio_pad_length(ncp->nciop, calcsize);
01186                 if(status != ENOERR)
01187                     return status;
01188             }
01189             
01190         }
01191 
01192         (void) ncio_close(ncp->nciop, 0);
01193         ncp->nciop = NULL;
01194 
01195         del_from_NCList(ncp);
01196 
01197         free_NC(ncp);
01198 
01199         return status;
01200 }
01201 
01202 
01203 int
01204 nc_delete(const char * path)
01205 {
01206         return nc_delete_mp(path, 0);
01207 }
01208 
01209 int
01210 nc_delete_mp(const char * path, int basepe)
01211 {
01212         NC *ncp;
01213         int status;
01214         size_t chunk = 512;
01215 
01216         ncp = new_NC(&chunk);
01217         if(ncp == NULL)
01218                 return NC_ENOMEM;
01219         
01220 #if defined(LOCKNUMREC) /* && _CRAYMPP */
01221         if (status = NC_init_pe(ncp, basepe)) {
01222                 return status;
01223         }
01224 #else
01225         /*
01226          * !_CRAYMPP, only pe 0 is valid
01227          */
01228         if(basepe != 0)
01229                 return NC_EINVAL;
01230 #endif
01231         status = ncio_open(path, NC_NOWRITE,
01232                 0, 0, &ncp->chunk,
01233                 &ncp->nciop, 0);
01234         if(status)
01235                 goto unwind_alloc;
01236 
01237         assert(ncp->flags == 0);
01238 
01239         status = nc_get_NC(ncp);
01240         if(status != NC_NOERR)
01241         {
01242                 /* Not a netcdf file, don't delete */
01243                 /* ??? is this the right semantic? what if it was just too big? */
01244                 (void) ncio_close(ncp->nciop, 0);
01245         }
01246         else
01247         {
01248                 /* ncio_close does the unlink */
01249                 status = ncio_close(ncp->nciop, 1); /* ncio_close does the unlink */
01250         }
01251 
01252         ncp->nciop = NULL;
01253 unwind_alloc:
01254         free_NC(ncp);
01255         return status;
01256 }
01257 
01258 
01259 /*
01260  * In data mode, same as ncclose.
01261  * In define mode, restore previous definition.
01262  * In create, remove the file.
01263  */
01264 int
01265 nc_abort(int ncid)
01266 {
01267         int status;
01268         NC *ncp;
01269         int doUnlink = 0;
01270 
01271         status = NC_check_id(ncid, &ncp); 
01272         if(status != NC_NOERR)
01273                 return status;
01274 
01275         doUnlink = NC_IsNew(ncp);
01276 
01277         if(ncp->old != NULL)
01278         {
01279                 /* a plain redef, not a create */
01280                 assert(!NC_IsNew(ncp));
01281                 assert(fIsSet(ncp->flags, NC_INDEF));
01282                 free_NC(ncp->old);
01283                 ncp->old = NULL;
01284                 fClr(ncp->flags, NC_INDEF);
01285         }
01286         else if(!NC_readonly(ncp))
01287         {
01288                 status = NC_sync(ncp);
01289                 if(status != NC_NOERR)
01290                         return status;
01291         }
01292 
01293 
01294         (void) ncio_close(ncp->nciop, doUnlink);
01295         ncp->nciop = NULL;
01296 
01297         del_from_NCList(ncp);
01298 
01299         free_NC(ncp);
01300 
01301         return NC_NOERR;
01302 }
01303 
01304 
01305 int
01306 nc_redef(int ncid)
01307 {
01308         int status;
01309         NC *ncp;
01310 
01311         status = NC_check_id(ncid, &ncp); 
01312         if(status != NC_NOERR)
01313                 return status;
01314 
01315         if(NC_readonly(ncp))
01316                 return NC_EPERM;
01317 
01318         if(NC_indef(ncp))
01319                 return NC_EINDEFINE;
01320 
01321         
01322         if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
01323         {
01324                 /* read in from disk */
01325                 status = read_NC(ncp);
01326                 if(status != NC_NOERR)
01327                         return status;
01328         }
01329 
01330         ncp->old = dup_NC(ncp);
01331         if(ncp->old == NULL)
01332                 return NC_ENOMEM;
01333 
01334         fSet(ncp->flags, NC_INDEF);
01335 
01336         return NC_NOERR;
01337 }
01338 
01339 
01340 int
01341 nc_inq(int ncid,
01342         int *ndimsp,
01343         int *nvarsp,
01344         int *nattsp,
01345         int *xtendimp)
01346 {
01347         int status;
01348         NC *ncp;
01349 
01350         status = NC_check_id(ncid, &ncp); 
01351         if(status != NC_NOERR)
01352                 return status;
01353 
01354         if(ndimsp != NULL)
01355                 *ndimsp = (int) ncp->dims.nelems;
01356         if(nvarsp != NULL)
01357                 *nvarsp = (int) ncp->vars.nelems;
01358         if(nattsp != NULL)
01359                 *nattsp = (int) ncp->attrs.nelems;
01360         if(xtendimp != NULL)
01361                 *xtendimp = find_NC_Udim(&ncp->dims, NULL);
01362 
01363         return NC_NOERR;
01364 }
01365 
01366 int 
01367 nc_inq_ndims(int ncid, int *ndimsp)
01368 {
01369         int status;
01370         NC *ncp;
01371 
01372         status = NC_check_id(ncid, &ncp); 
01373         if(status != NC_NOERR)
01374                 return status;
01375 
01376         if(ndimsp != NULL)
01377                 *ndimsp = (int) ncp->dims.nelems;
01378 
01379         return NC_NOERR;
01380 }
01381 
01382 int 
01383 nc_inq_nvars(int ncid, int *nvarsp)
01384 {
01385         int status;
01386         NC *ncp;
01387 
01388         status = NC_check_id(ncid, &ncp); 
01389         if(status != NC_NOERR)
01390                 return status;
01391 
01392         if(nvarsp != NULL)
01393                 *nvarsp = (int) ncp->vars.nelems;
01394 
01395         return NC_NOERR;
01396 }
01397 
01398 int 
01399 nc_inq_natts(int ncid, int *nattsp)
01400 {
01401         int status;
01402         NC *ncp;
01403 
01404         status = NC_check_id(ncid, &ncp); 
01405         if(status != NC_NOERR)
01406                 return status;
01407 
01408         if(nattsp != NULL)
01409                 *nattsp = (int) ncp->attrs.nelems;
01410 
01411         return NC_NOERR;
01412 }
01413 
01414 int 
01415 nc_inq_unlimdim(int ncid, int *xtendimp)
01416 {
01417         int status;
01418         NC *ncp;
01419 
01420         status = NC_check_id(ncid, &ncp); 
01421         if(status != NC_NOERR)
01422                 return status;
01423 
01424         if(xtendimp != NULL)
01425                 *xtendimp = find_NC_Udim(&ncp->dims, NULL);
01426 
01427         return NC_NOERR;
01428 }
01429 
01430 
01431 int
01432 nc_sync(int ncid)
01433 {
01434         int status;
01435         NC *ncp;
01436 
01437         status = NC_check_id(ncid, &ncp); 
01438         if(status != NC_NOERR)
01439                 return status;
01440 
01441         if(NC_indef(ncp))
01442                 return NC_EINDEFINE;
01443 
01444         if(NC_readonly(ncp))
01445         {
01446                 return read_NC(ncp);
01447         }
01448         /* else, read/write */
01449 
01450         status = NC_sync(ncp);
01451         if(status != NC_NOERR)
01452                 return status;
01453 
01454         return ncp->nciop->sync(ncp->nciop);
01455 }
01456 
01457 
01458 int
01459 nc_set_fill(int ncid,
01460         int fillmode, int *old_mode_ptr)
01461 {
01462         int status;
01463         NC *ncp;
01464         int oldmode;
01465 
01466         status = NC_check_id(ncid, &ncp); 
01467         if(status != NC_NOERR)
01468                 return status;
01469 
01470         if(NC_readonly(ncp))
01471                 return NC_EPERM;
01472 
01473         oldmode = fIsSet(ncp->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL;
01474 
01475         if(fillmode == NC_NOFILL)
01476         {
01477                 fSet(ncp->flags, NC_NOFILL);
01478         }
01479         else if(fillmode == NC_FILL)
01480         {
01481                 if(fIsSet(ncp->flags, NC_NOFILL))
01482                 {
01483                         /*
01484                          * We are changing back to fill mode
01485                          * so do a sync
01486                          */
01487                         status = NC_sync(ncp);
01488                         if(status != NC_NOERR)
01489                                 return status;
01490                 }
01491                 fClr(ncp->flags, NC_NOFILL);
01492         }
01493         else
01494         {
01495                 return NC_EINVAL; /* Invalid fillmode */
01496         }
01497 
01498         if(old_mode_ptr != NULL)
01499                 *old_mode_ptr = oldmode;
01500 
01501         return NC_NOERR;
01502 }
01503 
01504 #ifdef LOCKNUMREC
01505 
01506 /* create function versions of the NC_*_numrecs macros */
01507 size_t NC_get_numrecs(const NC *ncp) {
01508         shmem_t numrec;
01509         shmem_short_get(&numrec, (shmem_t *) ncp->lock + LOCKNUMREC_VALUE, 1,
01510                 ncp->lock[LOCKNUMREC_BASEPE]);
01511         return (size_t) numrec;
01512 }
01513 
01514 void NC_set_numrecs(NC *ncp, size_t nrecs) {
01515         shmem_t numrec = (shmem_t) nrecs;
01516         /* update local value too */
01517         ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrec;
01518         shmem_short_put((shmem_t *) ncp->lock + LOCKNUMREC_VALUE, &numrec, 1,
01519                 ncp->lock[LOCKNUMREC_BASEPE]);
01520 }
01521 
01522 void NC_increase_numrecs(NC *ncp, size_t nrecs) {
01523         /* this is only called in one place that's already protected
01524          * by a lock ... so don't worry about it */
01525         if (nrecs > NC_get_numrecs(ncp))
01526                 NC_set_numrecs(ncp, nrecs);
01527 }
01528 
01529 #endif /* LOCKNUMREC */
01530 
01531 /* everyone in communicator group will be executing this */
01532 /*ARGSUSED*/
01533 int
01534 nc_set_base_pe(int ncid, int pe)
01535 {
01536 #if _CRAYMPP && defined(LOCKNUMREC)
01537         int status;
01538         NC *ncp;
01539         shmem_t numrecs;
01540 
01541         if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
01542                 return status;
01543         }
01544         if (pe < 0 || pe >= _num_pes()) {
01545                 return NC_EINVAL; /* invalid base pe */
01546         }
01547 
01548         numrecs = (shmem_t) NC_get_numrecs(ncp);
01549 
01550         ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrecs;
01551 
01552         /* update serving & lock values for a "smooth" transition */
01553         /* note that the "real" server will being doing this as well */
01554         /* as all the rest in the group */
01555         /* must have syncronization before & after this step */
01556         shmem_short_get(
01557                 (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
01558                 (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
01559                 1, ncp->lock[LOCKNUMREC_BASEPE]);
01560 
01561         shmem_short_get(
01562                 (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
01563                 (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
01564                 1, ncp->lock[LOCKNUMREC_BASEPE]);
01565 
01566         /* complete transition */
01567         ncp->lock[LOCKNUMREC_BASEPE] = (ushmem_t) pe;
01568 
01569 #endif /* _CRAYMPP && LOCKNUMREC */
01570         return NC_NOERR;
01571 }
01572 
01573 /*ARGSUSED*/
01574 int
01575 nc_inq_base_pe(int ncid, int *pe)
01576 {
01577 #if _CRAYMPP && defined(LOCKNUMREC)
01578         int status;
01579         NC *ncp;
01580 
01581         if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
01582                 return status;
01583         }
01584 
01585         *pe = (int) ncp->lock[LOCKNUMREC_BASEPE];
01586 #else
01587         /*
01588          * !_CRAYMPP, only pe 0 is valid
01589          */
01590         *pe = 0;
01591 #endif /* _CRAYMPP && LOCKNUMREC */
01592         return NC_NOERR;
01593 }
01594 
01595 int
01596 nc_inq_format(int ncid, int *formatp)
01597 {
01598         int status;
01599         NC *ncp;
01600 
01601         status = NC_check_id(ncid, &ncp); 
01602         if(status != NC_NOERR)
01603                 return status;
01604 
01605         /* only need to check for netCDF-3 variants, since this is never called for netCDF-4 
01606            files */
01607         *formatp = fIsSet(ncp->flags, NC_64BIT_OFFSET) ? NC_FORMAT_64BIT 
01608             : NC_FORMAT_CLASSIC; 
01609         return NC_NOERR;
01610 }

Generated on Thu Mar 16 18:10:09 2006 for nco by  doxygen 1.4.4