12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559 |
- /*
- * Copyright 1996, University Corporation for Atmospheric Research
- * See netcdf/COPYRIGHT file for copying and redistribution conditions.
- */
- #include <config.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #if defined(LOCKNUMREC) /* && _CRAYMPP */
- # include <mpp/shmem.h>
- # include <intrinsics.h>
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include "nc.h"
- #include "ncdispatch.h"
- #include "nc3dispatch.h"
- #include "rnd.h"
- #include "ncx.h"
- /* This is the default create format for nc_create and nc__create. */
- int default_create_format = NC_FORMAT_CLASSIC;
- /* These have to do with version numbers. */
- #define MAGIC_NUM_LEN 4
- #define VER_CLASSIC 1
- #define VER_64BIT_OFFSET 2
- #define VER_HDF5 3
- int
- NC_check_id(int ncid, NC **ncpp)
- {
- NC* nc = find_in_NCList(ncid);
- if(nc == NULL) return NC_EBADID;
- if(ncpp) *ncpp = nc;
- return NC_NOERR;
- }
- static void
- free_NC(NC *ncp)
- {
- if(ncp == NULL)
- return;
- free_NC_dimarrayV(&ncp->dims);
- free_NC_attrarrayV(&ncp->attrs);
- free_NC_vararrayV(&ncp->vars);
- if (ncp->path)
- free(ncp->path);
- #if _CRAYMPP && defined(LOCKNUMREC)
- shfree(ncp);
- #else
- free(ncp);
- #endif /* _CRAYMPP && LOCKNUMREC */
- }
- static NC *
- new_NC(const size_t *chunkp, NC_Dispatch* dispatch)
- {
- NC *ncp;
- int stat = dispatch->new_nc(&ncp);
- if(stat) return NULL;
- ncp->xsz = MIN_NC_XSZ;
- assert(ncp->xsz == ncx_len_NC(ncp,0));
- ncp->chunk = chunkp != NULL ? *chunkp : NC_SIZEHINT_DEFAULT;
- return ncp;
- }
- static NC *
- dup_NC(const NC *ref)
- {
- NC *ncp;
- int stat = ref->dispatch->new_nc(&ncp);
- if(stat) return NULL;
- if(ncp == NULL)
- return NULL;
- if(dup_NC_dimarrayV(&ncp->dims, &ref->dims) != NC_NOERR)
- goto err;
- if(dup_NC_attrarrayV(&ncp->attrs, &ref->attrs) != NC_NOERR)
- goto err;
- if(dup_NC_vararrayV(&ncp->vars, &ref->vars) != NC_NOERR)
- goto err;
- ncp->xsz = ref->xsz;
- ncp->begin_var = ref->begin_var;
- ncp->begin_rec = ref->begin_rec;
- ncp->recsize = ref->recsize;
- NC_set_numrecs(ncp, NC_get_numrecs(ref));
- return ncp;
- err:
- free_NC(ncp);
- return NULL;
- }
- /*
- * Verify that this is a user nc_type
- * Formerly
- NCcktype()
- * Sense of the return is changed.
- */
- int
- nc_cktype(nc_type type)
- {
- switch((int)type){
- case NC_BYTE:
- case NC_CHAR:
- case NC_SHORT:
- case NC_INT:
- case NC_FLOAT:
- case NC_DOUBLE:
- return(NC_NOERR);
- }
- return(NC_EBADTYPE);
- }
- /*
- * How many objects of 'type'
- * will fit into xbufsize?
- */
- size_t
- ncx_howmany(nc_type type, size_t xbufsize)
- {
- switch(type){
- case NC_BYTE:
- case NC_CHAR:
- return xbufsize;
- case NC_SHORT:
- return xbufsize/X_SIZEOF_SHORT;
- case NC_INT:
- return xbufsize/X_SIZEOF_INT;
- case NC_FLOAT:
- return xbufsize/X_SIZEOF_FLOAT;
- case NC_DOUBLE:
- return xbufsize/X_SIZEOF_DOUBLE;
- default:
- assert("ncx_howmany: Bad type" == 0);
- return(0);
- }
- }
- #define D_RNDUP(x, align) _RNDUP(x, (off_t)(align))
- /*
- * Compute each variable's 'begin' offset,
- * update 'begin_rec' as well.
- */
- static int
- NC_begins(NC *ncp,
- size_t h_minfree, size_t v_align,
- size_t v_minfree, size_t r_align)
- {
- size_t ii;
- int sizeof_off_t;
- off_t index = 0;
- NC_var **vpp;
- NC_var *last = NULL;
- if(v_align == NC_ALIGN_CHUNK)
- v_align = ncp->chunk;
- if(r_align == NC_ALIGN_CHUNK)
- r_align = ncp->chunk;
- if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) {
- sizeof_off_t = 8;
- } else {
- sizeof_off_t = 4;
- }
-
- ncp->xsz = ncx_len_NC(ncp,sizeof_off_t);
- if(ncp->vars.nelems == 0)
- return NC_NOERR;
- /* only (re)calculate begin_var if there is not sufficient space in header
- or start of non-record variables is not aligned as requested by valign */
- if (ncp->begin_var < ncp->xsz + h_minfree ||
- ncp->begin_var != D_RNDUP(ncp->begin_var, v_align) )
- {
- index = (off_t) ncp->xsz;
- ncp->begin_var = D_RNDUP(index, v_align);
- if(ncp->begin_var < index + h_minfree)
- {
- ncp->begin_var = D_RNDUP(index + (off_t)h_minfree, v_align);
- }
- }
- index = ncp->begin_var;
- /* loop thru vars, first pass is for the 'non-record' vars */
- vpp = ncp->vars.value;
- for(ii = 0; ii < ncp->vars.nelems ; ii++, vpp++)
- {
- if( IS_RECVAR(*vpp) )
- {
- /* skip record variables on this pass */
- continue;
- }
- #if 0
- fprintf(stderr, " VAR %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
- #endif
- if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) )
- {
- return NC_EVARSIZE;
- }
- (*vpp)->begin = index;
- index += (*vpp)->len;
- }
- /* only (re)calculate begin_rec if there is not sufficient
- space at end of non-record variables or if start of record
- variables is not aligned as requested by r_align */
- if (ncp->begin_rec < index + v_minfree ||
- ncp->begin_rec != D_RNDUP(ncp->begin_rec, r_align) )
- {
- ncp->begin_rec = D_RNDUP(index, r_align);
- if(ncp->begin_rec < index + v_minfree)
- {
- ncp->begin_rec = D_RNDUP(index + (off_t)v_minfree, r_align);
- }
- }
- index = ncp->begin_rec;
- ncp->recsize = 0;
- /* loop thru vars, second pass is for the 'record' vars */
- vpp = (NC_var **)ncp->vars.value;
- for(ii = 0; ii < ncp->vars.nelems; ii++, vpp++)
- {
- if( !IS_RECVAR(*vpp) )
- {
- /* skip non-record variables on this pass */
- continue;
- }
- #if 0
- fprintf(stderr, " REC %d %s: %ld\n", ii, (*vpp)->name->cp, (long)index);
- #endif
- if( sizeof_off_t == 4 && (index > X_OFF_MAX || index < 0) )
- {
- return NC_EVARSIZE;
- }
- (*vpp)->begin = index;
- index += (*vpp)->len;
- /* check if record size must fit in 32-bits */
- #if SIZEOF_OFF_T == SIZEOF_SIZE_T && SIZEOF_SIZE_T == 4
- if( ncp->recsize > X_UINT_MAX - (*vpp)->len )
- {
- return NC_EVARSIZE;
- }
- #endif
- if((*vpp)->len != UINT32_MAX) /* flag for vars >= 2**32 bytes */
- ncp->recsize += (*vpp)->len;
- last = (*vpp);
- }
- /*
- * for special case of
- */
- if(last != NULL) {
- if(ncp->recsize == last->len) { /* exactly one record variable, pack value */
- ncp->recsize = *last->dsizes * last->xsz;
- } else if(last->len == UINT32_MAX) { /* huge last record variable */
- ncp->recsize += *last->dsizes * last->xsz;
- }
- }
- if(NC_IsNew(ncp))
- NC_set_numrecs(ncp, 0);
- return NC_NOERR;
- }
- /*
- * Read just the numrecs member.
- * (A relatively expensive way to do things.)
- */
- int
- read_numrecs(NC *ncp)
- {
- int status = NC_NOERR;
- const void *xp = NULL;
- size_t nrecs = NC_get_numrecs(ncp);
- assert(!NC_indef(ncp));
- #define NC_NUMRECS_OFFSET 4
- #define NC_NUMRECS_EXTENT 4
- status = ncio_get(ncp->nciop,
- NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, 0, (void **)&xp);
- /* cast away const */
- if(status != NC_NOERR)
- return status;
- status = ncx_get_size_t(&xp, &nrecs);
- (void) ncio_rel(ncp->nciop, NC_NUMRECS_OFFSET, 0);
- if(status == NC_NOERR)
- {
- NC_set_numrecs(ncp, nrecs);
- fClr(ncp->flags, NC_NDIRTY);
- }
- return status;
- }
- /*
- * Write out just the numrecs member.
- * (A relatively expensive way to do things.)
- */
- int
- write_numrecs(NC *ncp)
- {
- int status = NC_NOERR;
- void *xp = NULL;
- assert(!NC_readonly(ncp));
- assert(!NC_indef(ncp));
- status = ncio_get(ncp->nciop,
- NC_NUMRECS_OFFSET, NC_NUMRECS_EXTENT, RGN_WRITE, &xp);
- if(status != NC_NOERR)
- return status;
- {
- const size_t nrecs = NC_get_numrecs(ncp);
- status = ncx_put_size_t(&xp, &nrecs);
- }
- (void) ncio_rel(ncp->nciop, NC_NUMRECS_OFFSET, RGN_MODIFIED);
- if(status == NC_NOERR)
- fClr(ncp->flags, NC_NDIRTY);
- return status;
- }
- /*
- * Read in the header
- * It is expensive.
- */
- static int
- read_NC(NC *ncp)
- {
- int status = NC_NOERR;
- free_NC_dimarrayV(&ncp->dims);
- free_NC_attrarrayV(&ncp->attrs);
- free_NC_vararrayV(&ncp->vars);
- status = nc_get_NC(ncp);
- if(status == NC_NOERR)
- fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
- return status;
- }
- /*
- * Write out the header
- */
- static int
- write_NC(NC *ncp)
- {
- int status = NC_NOERR;
- assert(!NC_readonly(ncp));
- status = ncx_put_NC(ncp, NULL, 0, 0);
- if(status == NC_NOERR)
- fClr(ncp->flags, NC_NDIRTY | NC_HDIRTY);
- return status;
- }
- /*
- * Write the header or the numrecs if necessary.
- */
- int
- NC_sync(NC *ncp)
- {
- assert(!NC_readonly(ncp));
- if(NC_hdirty(ncp))
- {
- return write_NC(ncp);
- }
- /* else */
- if(NC_ndirty(ncp))
- {
- return write_numrecs(ncp);
- }
- /* else */
- return NC_NOERR;
- }
- /*
- * Initialize the 'non-record' variables.
- */
- static int
- fillerup(NC *ncp)
- {
- int status = NC_NOERR;
- size_t ii;
- NC_var **varpp;
- assert(!NC_readonly(ncp));
- assert(NC_dofill(ncp));
- /* loop thru vars */
- varpp = ncp->vars.value;
- for(ii = 0; ii < ncp->vars.nelems; ii++, varpp++)
- {
- if(IS_RECVAR(*varpp))
- {
- /* skip record variables */
- continue;
- }
- status = fill_NC_var(ncp, *varpp, (*varpp)->len, 0);
- if(status != NC_NOERR)
- break;
- }
- return status;
- }
- /* Begin endef */
- /*
- */
- static int
- fill_added_recs(NC *gnu, NC *old)
- {
- NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
- const int old_nrecs = (int) NC_get_numrecs(old);
- int recno = 0;
- NC_var **vpp = gnu_varpp;
- NC_var *const *const end = &vpp[gnu->vars.nelems];
- int numrecvars = 0;
- /* Determine if there is only one record variable. If so, we
- must treat as a special case because there's no record padding */
- for(; vpp < end; vpp++) {
- if(IS_RECVAR(*vpp)) {
- numrecvars++;
- }
- }
- for(; recno < old_nrecs; recno++)
- {
- int varid = (int)old->vars.nelems;
- for(; varid < (int)gnu->vars.nelems; varid++)
- {
- const NC_var *const gnu_varp = *(gnu_varpp + varid);
- if(!IS_RECVAR(gnu_varp))
- {
- /* skip non-record variables */
- continue;
- }
- /* else */
- {
- size_t varsize = numrecvars == 1 ? gnu->recsize : gnu_varp->len;
- const int status = fill_NC_var(gnu, gnu_varp, varsize, recno);
- if(status != NC_NOERR)
- return status;
- }
- }
- }
- return NC_NOERR;
- }
- /*
- */
- static int
- fill_added(NC *gnu, NC *old)
- {
- NC_var ** const gnu_varpp = (NC_var **)gnu->vars.value;
- int varid = (int)old->vars.nelems;
- for(; varid < (int)gnu->vars.nelems; varid++)
- {
- const NC_var *const gnu_varp = *(gnu_varpp + varid);
- if(IS_RECVAR(gnu_varp))
- {
- /* skip record variables */
- continue;
- }
- /* else */
- {
- const int status = fill_NC_var(gnu, gnu_varp, gnu_varp->len, 0);
- if(status != NC_NOERR)
- return status;
- }
- }
- return NC_NOERR;
- }
- /*
- * Move the records "out".
- * Fill as needed.
- */
- static int
- move_recs_r(NC *gnu, NC *old)
- {
- int status;
- int recno;
- int varid;
- NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
- NC_var **old_varpp = (NC_var **)old->vars.value;
- NC_var *gnu_varp;
- NC_var *old_varp;
- off_t gnu_off;
- off_t old_off;
- const size_t old_nrecs = NC_get_numrecs(old);
-
- /* Don't parallelize this loop */
- for(recno = (int)old_nrecs -1; recno >= 0; recno--)
- {
- /* Don't parallelize this loop */
- for(varid = (int)old->vars.nelems -1; varid >= 0; varid--)
- {
- gnu_varp = *(gnu_varpp + varid);
- if(!IS_RECVAR(gnu_varp))
- {
- /* skip non-record variables on this pass */
- continue;
- }
- /* else */
- /* else, a pre-existing variable */
- old_varp = *(old_varpp + varid);
- gnu_off = gnu_varp->begin + (off_t)(gnu->recsize * recno);
- old_off = old_varp->begin + (off_t)(old->recsize * recno);
- if(gnu_off == old_off)
- continue; /* nothing to do */
- assert(gnu_off > old_off);
-
- status = ncio_move(gnu->nciop, gnu_off, old_off,
- old_varp->len, 0);
- if(status != NC_NOERR)
- return status;
-
- }
- }
- NC_set_numrecs(gnu, old_nrecs);
- return NC_NOERR;
- }
- /*
- * Move the "non record" variables "out".
- * Fill as needed.
- */
- static int
- move_vars_r(NC *gnu, NC *old)
- {
- int status;
- int varid;
- NC_var **gnu_varpp = (NC_var **)gnu->vars.value;
- NC_var **old_varpp = (NC_var **)old->vars.value;
- NC_var *gnu_varp;
- NC_var *old_varp;
- off_t gnu_off;
- off_t old_off;
-
- /* Don't parallelize this loop */
- for(varid = (int)old->vars.nelems -1;
- varid >= 0; varid--)
- {
- gnu_varp = *(gnu_varpp + varid);
- if(IS_RECVAR(gnu_varp))
- {
- /* skip record variables on this pass */
- continue;
- }
- /* else */
- old_varp = *(old_varpp + varid);
- gnu_off = gnu_varp->begin;
- old_off = old_varp->begin;
-
- if(gnu_off == old_off)
- continue; /* nothing to do */
- assert(gnu_off > old_off);
- status = ncio_move(gnu->nciop, gnu_off, old_off,
- old_varp->len, 0);
- if(status != NC_NOERR)
- return status;
-
- }
- return NC_NOERR;
- }
- /*
- * Given a valid ncp, return NC_EVARSIZE if any variable has a bad len
- * (product of non-rec dim sizes too large), else return NC_NOERR.
- */
- static int
- NC_check_vlens(NC *ncp)
- {
- NC_var **vpp;
- /* maximum permitted variable size (or size of one record's worth
- of a record variable) in bytes. This is different for format 1
- and format 2. */
- size_t vlen_max;
- size_t ii;
- size_t large_vars_count;
- size_t rec_vars_count;
- int last = 0;
- if(ncp->vars.nelems == 0)
- return NC_NOERR;
- if ((ncp->flags & NC_64BIT_OFFSET) && sizeof(off_t) > 4) {
- /* CDF2 format and LFS */
- vlen_max = X_UINT_MAX - 3; /* "- 3" handles rounded-up size */
- } else {
- /* CDF1 format */
- vlen_max = X_INT_MAX - 3;
- }
- /* Loop through vars, first pass is for non-record variables. */
- large_vars_count = 0;
- rec_vars_count = 0;
- vpp = ncp->vars.value;
- for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
- if( !IS_RECVAR(*vpp) ) {
- last = 0;
- if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
- large_vars_count++;
- last = 1;
- }
- } else {
- rec_vars_count++;
- }
- }
- /* OK if last non-record variable size too large, since not used to
- compute an offset */
- if( large_vars_count > 1) { /* only one "too-large" variable allowed */
- return NC_EVARSIZE;
- }
- /* and it has to be the last one */
- if( large_vars_count == 1 && last == 0) {
- return NC_EVARSIZE;
- }
- if( rec_vars_count > 0 ) {
- /* and if it's the last one, there can't be any record variables */
- if( large_vars_count == 1 && last == 1) {
- return NC_EVARSIZE;
- }
- /* Loop through vars, second pass is for record variables. */
- large_vars_count = 0;
- vpp = ncp->vars.value;
- for (ii = 0; ii < ncp->vars.nelems; ii++, vpp++) {
- if( IS_RECVAR(*vpp) ) {
- last = 0;
- if( NC_check_vlen(*vpp, vlen_max) == 0 ) {
- large_vars_count++;
- last = 1;
- }
- }
- }
- /* OK if last record variable size too large, since not used to
- compute an offset */
- if( large_vars_count > 1) { /* only one "too-large" variable allowed */
- return NC_EVARSIZE;
- }
- /* and it has to be the last one */
- if( large_vars_count == 1 && last == 0) {
- return NC_EVARSIZE;
- }
- }
- return NC_NOERR;
- }
- /*
- * End define mode.
- * Common code for ncendef, ncclose(endef)
- * Flushes I/O buffers.
- */
- static int
- NC_endef(NC *ncp,
- size_t h_minfree, size_t v_align,
- size_t v_minfree, size_t r_align)
- {
- int status = NC_NOERR;
- assert(!NC_readonly(ncp));
- assert(NC_indef(ncp));
- status = NC_check_vlens(ncp);
- if(status != NC_NOERR)
- return status;
- status = NC_begins(ncp, h_minfree, v_align, v_minfree, r_align);
- if(status != NC_NOERR)
- return status;
- if(ncp->old != NULL)
- {
- /* a plain redef, not a create */
- assert(!NC_IsNew(ncp));
- assert(fIsSet(ncp->flags, NC_INDEF));
- assert(ncp->begin_rec >= ncp->old->begin_rec);
- assert(ncp->begin_var >= ncp->old->begin_var);
- if(ncp->vars.nelems != 0)
- {
- if(ncp->begin_rec > ncp->old->begin_rec)
- {
- status = move_recs_r(ncp, ncp->old);
- if(status != NC_NOERR)
- return status;
- if(ncp->begin_var > ncp->old->begin_var)
- {
- status = move_vars_r(ncp, ncp->old);
- if(status != NC_NOERR)
- return status;
- }
- /* else if (ncp->begin_var == ncp->old->begin_var) { NOOP } */
- }
- else
- { /* Even if (ncp->begin_rec == ncp->old->begin_rec)
- and (ncp->begin_var == ncp->old->begin_var)
- might still have added a new record variable */
- if(ncp->recsize > ncp->old->recsize)
- {
- status = move_recs_r(ncp, ncp->old);
- if(status != NC_NOERR)
- return status;
- }
- }
- }
- }
- status = write_NC(ncp);
- if(status != NC_NOERR)
- return status;
- if(NC_dofill(ncp))
- {
- if(NC_IsNew(ncp))
- {
- status = fillerup(ncp);
- if(status != NC_NOERR)
- return status;
-
- }
- else if(ncp->vars.nelems > ncp->old->vars.nelems)
- {
- status = fill_added(ncp, ncp->old);
- if(status != NC_NOERR)
- return status;
- status = fill_added_recs(ncp, ncp->old);
- if(status != NC_NOERR)
- return status;
- }
- }
- if(ncp->old != NULL)
- {
- free_NC(ncp->old);
- ncp->old = NULL;
- }
- fClr(ncp->flags, NC_CREAT | NC_INDEF);
- return ncio_sync(ncp->nciop);
- }
- #ifdef LOCKNUMREC
- static int
- NC_init_pe(NC *ncp, int basepe) {
- if (basepe < 0 || basepe >= _num_pes()) {
- return NC_EINVAL; /* invalid base pe */
- }
- /* initialize common values */
- ncp->lock[LOCKNUMREC_VALUE] = 0;
- ncp->lock[LOCKNUMREC_LOCK] = 0;
- ncp->lock[LOCKNUMREC_SERVING] = 0;
- ncp->lock[LOCKNUMREC_BASEPE] = basepe;
- return NC_NOERR;
- }
- #endif
- /*
- * Compute the expected size of the file.
- */
- int
- NC_calcsize(const NC *ncp, off_t *calcsizep)
- {
- NC_var **vpp = (NC_var **)ncp->vars.value;
- NC_var *const *const end = &vpp[ncp->vars.nelems];
- NC_var *last_fix = NULL; /* last "non-record" var */
- int numrecvars = 0; /* number of record variables */
- if(ncp->vars.nelems == 0) { /* no non-record variables and
- no record variables */
- *calcsizep = ncp->xsz; /* size of header */
- return NC_NOERR;
- }
- for( /*NADA*/; vpp < end; vpp++) {
- if(IS_RECVAR(*vpp)) {
- numrecvars++;
- } else {
- last_fix = *vpp;
- }
- }
- if(numrecvars == 0) {
- off_t varsize;
- assert(last_fix != NULL);
- varsize = last_fix->len;
- if(last_fix->len == X_UINT_MAX) { /* huge last fixed var */
- int i;
- varsize = 1;
- for(i = 0; i < last_fix->ndims; i++ ) {
- varsize *= last_fix->shape[i];
- }
- }
- *calcsizep = last_fix->begin + varsize;
- /*last_var = last_fix;*/
- } else { /* we have at least one record variable */
- *calcsizep = ncp->begin_rec + ncp->numrecs * ncp->recsize;
- }
- return NC_NOERR;
- }
- /* Public */
- int NC3_new_nc(NC** ncpp)
- {
- NC *ncp;
- #if _CRAYMPP && defined(LOCKNUMREC)
- ncp = (NC *) shmalloc(sizeof(NC));
- #else
- ncp = (NC *) malloc(sizeof(NC));
- #endif /* _CRAYMPP && LOCKNUMREC */
- if(ncp == NULL)
- return NC_ENOMEM;
- (void) memset(ncp, 0, sizeof(NC));
- ncp->xsz = MIN_NC_XSZ;
- assert(ncp->xsz == ncx_len_NC(ncp,0));
-
- if(ncpp) *ncpp = ncp;
- return NC_NOERR;
- }
- /* WARNING: SIGNATURE CHANGE */
- int
- NC3_create(const char *path, int ioflags,
- size_t initialsz, int basepe,
- size_t *chunksizehintp,
- int use_parallel, void* parameters,
- NC_Dispatch* dispatch, NC** ncpp)
- {
- NC *ncp;
- int status;
- void *xp = NULL;
- int sizeof_off_t = 0;
- #if ALWAYS_NC_SHARE /* DEBUG */
- fSet(ioflags, NC_SHARE);
- #endif
- ncp = new_NC(chunksizehintp,dispatch);
- if(ncp == NULL)
- return NC_ENOMEM;
- #if defined(LOCKNUMREC) /* && _CRAYMPP */
- if (status = NC_init_pe(ncp, basepe)) {
- return status;
- }
- #else
- /*
- * !_CRAYMPP, only pe 0 is valid
- */
- if(basepe != 0)
- return NC_EINVAL;
- #endif
- assert(ncp->flags == 0);
- /* Apply default create format. */
- if (default_create_format == NC_FORMAT_64BIT)
- ioflags |= NC_64BIT_OFFSET;
- if (fIsSet(ioflags, NC_64BIT_OFFSET)) {
- fSet(ncp->flags, NC_64BIT_OFFSET);
- sizeof_off_t = 8;
- } else {
- sizeof_off_t = 4;
- }
- assert(ncp->xsz == ncx_len_NC(ncp,sizeof_off_t));
-
- status = ncio_create(path, ioflags, initialsz,
- 0, ncp->xsz, &ncp->chunk,
- &ncp->nciop, &xp);
- if(status != NC_NOERR)
- {
- /* translate error status */
- if(status == EEXIST)
- status = NC_EEXIST;
- goto unwind_alloc;
- }
- fSet(ncp->flags, NC_CREAT);
- if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
- {
- /*
- * NC_SHARE implies sync up the number of records as well.
- * (File format version one.)
- * Note that other header changes are not shared
- * automatically. Some sort of IPC (external to this package)
- * would be used to trigger a call to nc_sync().
- */
- fSet(ncp->flags, NC_NSYNC);
- }
- status = ncx_put_NC(ncp, &xp, sizeof_off_t, ncp->xsz);
- if(status != NC_NOERR)
- goto unwind_ioc;
- add_to_NCList(ncp);
- if(chunksizehintp != NULL)
- *chunksizehintp = ncp->chunk;
- ncp->int_ncid = ncp->nciop->fd;
- if(ncpp) *ncpp = ncp;
- return NC_NOERR;
- unwind_ioc:
- (void) ncio_close(ncp->nciop, 1); /* N.B.: unlink */
- ncp->nciop = NULL;
- /*FALLTHRU*/
- unwind_alloc:
- free_NC(ncp);
- return status;
- }
- /* This function sets a default create flag that will be logically
- or'd to whatever flags are passed into nc_create for all future
- calls to nc_create.
- Valid default create flags are NC_64BIT_OFFSET, NC_CLOBBER,
- NC_LOCK, NC_SHARE. */
- int
- nc_set_default_format(int format, int *old_formatp)
- {
- /* Return existing format if desired. */
- if (old_formatp)
- *old_formatp = default_create_format;
- /* Make sure only valid format is set. */
- #ifdef USE_NETCDF4
- if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT &&
- format != NC_FORMAT_NETCDF4 && format != NC_FORMAT_NETCDF4_CLASSIC)
- return NC_EINVAL;
- #else
- if (format != NC_FORMAT_CLASSIC && format != NC_FORMAT_64BIT)
- return NC_EINVAL;
- #endif
- default_create_format = format;
- return NC_NOERR;
- }
- int
- NC3_open(const char * path, int ioflags,
- int basepe, size_t *chunksizehintp,
- int use_parallel,void* parameters,
- NC_Dispatch* dispatch, NC** ncpp)
- {
- NC *ncp;
- int status;
- #if ALWAYS_NC_SHARE /* DEBUG */
- fSet(ioflags, NC_SHARE);
- #endif
- ncp = new_NC(chunksizehintp,dispatch);
- if(ncp == NULL)
- return NC_ENOMEM;
- #if defined(LOCKNUMREC) /* && _CRAYMPP */
- if (status = NC_init_pe(ncp, basepe)) {
- return status;
- }
- #else
- /*
- * !_CRAYMPP, only pe 0 is valid
- */
- if(basepe != 0)
- return NC_EINVAL;
- #endif
- status = ncio_open(path, ioflags, 0, 0, &ncp->chunk, &ncp->nciop, 0);
- if(status)
- goto unwind_alloc;
- assert(ncp->flags == 0);
- if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
- {
- /*
- * NC_SHARE implies sync up the number of records as well.
- * (File format version one.)
- * Note that other header changes are not shared
- * automatically. Some sort of IPC (external to this package)
- * would be used to trigger a call to nc_sync().
- */
- fSet(ncp->flags, NC_NSYNC);
- }
- status = nc_get_NC(ncp);
- if(status != NC_NOERR)
- goto unwind_ioc;
- add_to_NCList(ncp);
- if(chunksizehintp != NULL)
- *chunksizehintp = ncp->chunk;
- ncp->int_ncid = ncp->nciop->fd;
- if(ncpp) *ncpp = ncp;
- return NC_NOERR;
- unwind_ioc:
- (void) ncio_close(ncp->nciop, 0);
- ncp->nciop = NULL;
- /*FALLTHRU*/
- unwind_alloc:
- free_NC(ncp);
- return status;
- }
- int
- NC3__enddef(int ncid,
- size_t h_minfree, size_t v_align,
- size_t v_minfree, size_t r_align)
- {
- int status;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(!NC_indef(ncp))
- return(NC_ENOTINDEFINE);
- return (NC_endef(ncp, h_minfree, v_align, v_minfree, r_align));
- }
- int
- NC3_close(int ncid)
- {
- int status = NC_NOERR;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(NC_indef(ncp))
- {
- status = NC_endef(ncp, 0, 1, 0, 1); /* TODO: defaults */
- if(status != NC_NOERR )
- {
- (void) nc_abort(ncid);
- return status;
- }
- }
- else if(!NC_readonly(ncp))
- {
- status = NC_sync(ncp);
- /* flush buffers before any filesize comparisons */
- (void) ncio_sync(ncp->nciop);
- }
- /*
- * If file opened for writing and filesize is less than
- * what it should be (due to previous use of NOFILL mode),
- * pad it to correct size, as reported by NC_calcsize().
- */
- if (status == ENOERR) {
- off_t filesize; /* current size of open file */
- off_t calcsize; /* calculated file size, from header */
- status = ncio_filesize(ncp->nciop, &filesize);
- if(status != ENOERR)
- return status;
- status = NC_calcsize(ncp, &calcsize);
- if(status != NC_NOERR)
- return status;
- if(filesize < calcsize && !NC_readonly(ncp)) {
- status = ncio_pad_length(ncp->nciop, calcsize);
- if(status != ENOERR)
- return status;
- }
- }
- (void) ncio_close(ncp->nciop, 0);
- ncp->nciop = NULL;
- del_from_NCList(ncp);
- free_NC(ncp);
- return status;
- }
- /*
- * In data mode, same as ncclose.
- * In define mode, restore previous definition.
- * In create, remove the file.
- */
- int
- NC3_abort(int ncid)
- {
- int status;
- NC *ncp;
- int doUnlink = 0;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- doUnlink = NC_IsNew(ncp);
- if(ncp->old != NULL)
- {
- /* a plain redef, not a create */
- assert(!NC_IsNew(ncp));
- assert(fIsSet(ncp->flags, NC_INDEF));
- free_NC(ncp->old);
- ncp->old = NULL;
- fClr(ncp->flags, NC_INDEF);
- }
- else if(!NC_readonly(ncp))
- {
- status = NC_sync(ncp);
- if(status != NC_NOERR)
- return status;
- }
- (void) ncio_close(ncp->nciop, doUnlink);
- ncp->nciop = NULL;
- del_from_NCList(ncp);
- free_NC(ncp);
- return NC_NOERR;
- }
- int
- NC3_redef(int ncid)
- {
- int status;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(NC_readonly(ncp))
- return NC_EPERM;
- if(NC_indef(ncp))
- return NC_EINDEFINE;
-
- if(fIsSet(ncp->nciop->ioflags, NC_SHARE))
- {
- /* read in from disk */
- status = read_NC(ncp);
- if(status != NC_NOERR)
- return status;
- }
- ncp->old = dup_NC(ncp);
- if(ncp->old == NULL)
- return NC_ENOMEM;
- fSet(ncp->flags, NC_INDEF);
- return NC_NOERR;
- }
- int
- NC3_inq(int ncid,
- int *ndimsp,
- int *nvarsp,
- int *nattsp,
- int *xtendimp)
- {
- int status;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(ndimsp != NULL)
- *ndimsp = (int) ncp->dims.nelems;
- if(nvarsp != NULL)
- *nvarsp = (int) ncp->vars.nelems;
- if(nattsp != NULL)
- *nattsp = (int) ncp->attrs.nelems;
- if(xtendimp != NULL)
- *xtendimp = find_NC_Udim(&ncp->dims, NULL);
- return NC_NOERR;
- }
- int
- NC3_inq_unlimdim(int ncid, int *xtendimp)
- {
- int status;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(xtendimp != NULL)
- *xtendimp = find_NC_Udim(&ncp->dims, NULL);
- return NC_NOERR;
- }
- int
- NC3_sync(int ncid)
- {
- int status;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(NC_indef(ncp))
- return NC_EINDEFINE;
- if(NC_readonly(ncp))
- {
- return read_NC(ncp);
- }
- /* else, read/write */
- status = NC_sync(ncp);
- if(status != NC_NOERR)
- return status;
- status = ncio_sync(ncp->nciop);
- if(status != NC_NOERR)
- return status;
- #ifdef USE_FSYNC
- /* may improve concurrent access, but slows performance if
- * called frequently */
- #ifndef WIN32
- status = fsync(ncp->nciop->fd);
- #else
- status = _commit(ncp->nciop->fd);
- #endif /* WIN32 */
- #endif /* USE_FSYNC */
- return status;
- }
- int
- NC3_set_fill(int ncid,
- int fillmode, int *old_mode_ptr)
- {
- int status;
- NC *ncp;
- int oldmode;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- if(NC_readonly(ncp))
- return NC_EPERM;
- oldmode = fIsSet(ncp->flags, NC_NOFILL) ? NC_NOFILL : NC_FILL;
- if(fillmode == NC_NOFILL)
- {
- fSet(ncp->flags, NC_NOFILL);
- }
- else if(fillmode == NC_FILL)
- {
- if(fIsSet(ncp->flags, NC_NOFILL))
- {
- /*
- * We are changing back to fill mode
- * so do a sync
- */
- status = NC_sync(ncp);
- if(status != NC_NOERR)
- return status;
- }
- fClr(ncp->flags, NC_NOFILL);
- }
- else
- {
- return NC_EINVAL; /* Invalid fillmode */
- }
- if(old_mode_ptr != NULL)
- *old_mode_ptr = oldmode;
- return NC_NOERR;
- }
- #ifdef LOCKNUMREC
- /* create function versions of the NC_*_numrecs macros */
- size_t
- NC_get_numrecs(const NC *ncp) {
- shmem_t numrec;
- shmem_short_get(&numrec, (shmem_t *) ncp->lock + LOCKNUMREC_VALUE, 1,
- ncp->lock[LOCKNUMREC_BASEPE]);
- return (size_t) numrec;
- }
- void
- NC_set_numrecs(NC *ncp, size_t nrecs)
- {
- shmem_t numrec = (shmem_t) nrecs;
- /* update local value too */
- ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrec;
- shmem_short_put((shmem_t *) ncp->lock + LOCKNUMREC_VALUE, &numrec, 1,
- ncp->lock[LOCKNUMREC_BASEPE]);
- }
- void NC_increase_numrecs(NC *ncp, size_t nrecs)
- {
- /* this is only called in one place that's already protected
- * by a lock ... so don't worry about it */
- if (nrecs > NC_get_numrecs(ncp))
- NC_set_numrecs(ncp, nrecs);
- }
- #endif /* LOCKNUMREC */
- /* everyone in communicator group will be executing this */
- /*ARGSUSED*/
- int
- NC3_set_base_pe(int ncid, int pe)
- {
- #if _CRAYMPP && defined(LOCKNUMREC)
- int status;
- NC *ncp;
- shmem_t numrecs;
- if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
- return status;
- }
- if (pe < 0 || pe >= _num_pes()) {
- return NC_EINVAL; /* invalid base pe */
- }
- numrecs = (shmem_t) NC_get_numrecs(ncp);
- ncp->lock[LOCKNUMREC_VALUE] = (ushmem_t) numrecs;
- /* update serving & lock values for a "smooth" transition */
- /* note that the "real" server will being doing this as well */
- /* as all the rest in the group */
- /* must have syncronization before & after this step */
- shmem_short_get(
- (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
- (shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
- 1, ncp->lock[LOCKNUMREC_BASEPE]);
- shmem_short_get(
- (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
- (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
- 1, ncp->lock[LOCKNUMREC_BASEPE]);
- /* complete transition */
- ncp->lock[LOCKNUMREC_BASEPE] = (ushmem_t) pe;
- #endif /* _CRAYMPP && LOCKNUMREC */
- return NC_NOERR;
- }
- /*ARGSUSED*/
- int
- NC3_inq_base_pe(int ncid, int *pe)
- {
- #if _CRAYMPP && defined(LOCKNUMREC)
- int status;
- NC *ncp;
- if ((status = NC_check_id(ncid, &ncp)) != NC_NOERR) {
- return status;
- }
- *pe = (int) ncp->lock[LOCKNUMREC_BASEPE];
- #else
- /*
- * !_CRAYMPP, only pe 0 is valid
- */
- *pe = 0;
- #endif /* _CRAYMPP && LOCKNUMREC */
- return NC_NOERR;
- }
- int
- NC3_inq_format(int ncid, int *formatp)
- {
- int status;
- NC *ncp;
- status = NC_check_id(ncid, &ncp);
- if(status != NC_NOERR)
- return status;
- /* only need to check for netCDF-3 variants, since this is never called for netCDF-4
- files */
- *formatp = fIsSet(ncp->flags, NC_64BIT_OFFSET) ? NC_FORMAT_64BIT
- : NC_FORMAT_CLASSIC;
- return NC_NOERR;
- }
- /* The sizes of types may vary from platform to platform, but within
- * netCDF files, type sizes are fixed. */
- #define NC_BYTE_LEN 1
- #define NC_CHAR_LEN 1
- #define NC_SHORT_LEN 2
- #define NC_INT_LEN 4
- #define NC_FLOAT_LEN 4
- #define NC_DOUBLE_LEN 8
- #define NUM_ATOMIC_TYPES 6
- /* This netCDF-4 function proved so popular that a netCDF-classic
- * version is provided. You're welcome. */
- int
- NC3_inq_type(int ncid, nc_type typeid, char *name, size_t *size)
- {
- int atomic_size[NUM_ATOMIC_TYPES] = {NC_BYTE_LEN, NC_CHAR_LEN, NC_SHORT_LEN,
- NC_INT_LEN, NC_FLOAT_LEN, NC_DOUBLE_LEN};
- char atomic_name[NUM_ATOMIC_TYPES][NC_MAX_NAME + 1] = {"byte", "char", "short",
- "int", "float", "double"};
-
- /* Only netCDF classic model needs to be handled. */
- if (typeid < NC_BYTE || typeid > NC_DOUBLE)
- return NC_EBADTYPE;
- /* Give the user the values they want. Subtract one because types
- * are numbered starting at 1, not 0. */
- if (name)
- strcpy(name, atomic_name[typeid - 1]);
- if (size)
- *size = atomic_size[typeid - 1];
- return NC_NOERR;
- }
- int
- nc_delete_mp(const char * path, int basepe)
- {
- NC *ncp;
- int status;
- size_t chunk = 512;
- status = NC3_new_nc(&ncp);
- if(status) return status;
- ncp->chunk = chunk;
-
- #if defined(LOCKNUMREC) /* && _CRAYMPP */
- if (status = NC_init_pe(ncp, basepe)) {
- return status;
- }
- #else
- /*
- * !_CRAYMPP, only pe 0 is valid
- */
- if(basepe != 0)
- return NC_EINVAL;
- #endif
- status = ncio_open(path, NC_NOWRITE,
- 0, 0, &ncp->chunk,
- &ncp->nciop, 0);
- if(status)
- goto unwind_alloc;
- assert(ncp->flags == 0);
- status = nc_get_NC(ncp);
- if(status != NC_NOERR)
- {
- /* Not a netcdf file, don't delete */
- /* ??? is this the right semantic? what if it was just too big? */
- (void) ncio_close(ncp->nciop, 0);
- }
- else
- {
- /* ncio_close does the unlink */
- status = ncio_close(ncp->nciop, 1); /* ncio_close does the unlink */
- }
- ncp->nciop = NULL;
- ncp->nciop = NULL;
- unwind_alloc:
- free_NC(ncp);
- return status;
- }
- int
- nc_delete(const char * path)
- {
- return nc_delete_mp(path, 0);
- }
|