/* * 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 = ncp->nciop->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) ncp->nciop->rel(ncp->nciop, NC_NUMRECS_OFFSET, 0); if(status == NC_NOERR) { NC_set_numrecs(ncp, nrecs); fClr(ncp->flags, NC_NDIRTY); } return status; }
static NC * dup_NC(const NC *ref) { NC *ncp; #if _CRAYMPP && defined(LOCKNUMREC) ncp = (NC *) shmalloc(sizeof(NC)); #else ncp = (NC *) malloc(sizeof(NC)); #endif /* _CRAYMPP && LOCKNUMREC */ if(ncp == NULL) return NULL; (void) memset(ncp, 0, sizeof(NC)); 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; }
/* * 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 = gnu->nciop->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; }
static NCerror builddims(NCDAPCOMMON* dapcomm) { int i; NCerror ncstat = NC_NOERR; int dimid; NClist* dimset = NULL; NC* drno = dapcomm->controller; NC* ncsub; char* definename; /* collect all dimensions from variables */ dimset = dapcomm->cdf.dimnodes; /* Sort by fullname just for the fun of it */ for(;;) { int last = nclistlength(dimset) - 1; int swap = 0; for(i=0;i<last;i++) { CDFnode* dim1 = (CDFnode*)nclistget(dimset,i); CDFnode* dim2 = (CDFnode*)nclistget(dimset,i+1); if(strcmp(dim1->ncfullname,dim2->ncfullname) > 0) { nclistset(dimset,i,(ncelem)dim2); nclistset(dimset,i+1,(ncelem)dim1); swap = 1; break; } } if(!swap) break; } /* Define unlimited only if needed */ if(dapcomm->cdf.recorddim != NULL) { CDFnode* unlimited = dapcomm->cdf.recorddim; definename = getdefinename(unlimited); ncstat = nc_def_dim(drno->substrate, definename, NC_UNLIMITED, &unlimited->ncid); nullfree(definename); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} /* get the id for the substrate */ ncstat = NC_check_id(drno->substrate,&ncsub); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} /* Set the effective size of UNLIMITED; note that this cannot be done thru the normal API.*/ NC_set_numrecs(ncsub,unlimited->dim.declsize); } for(i=0;i<nclistlength(dimset);i++) { CDFnode* dim = (CDFnode*)nclistget(dimset,i); if(dim->dim.basedim != NULL) continue; /* handle below */ if(DIMFLAG(dim,CDFDIMRECORD)) continue; /* defined above */ #ifdef DEBUG1 fprintf(stderr,"define: dim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize); #endif definename = getdefinename(dim); ncstat = nc_def_dim(drno->substrate,definename,dim->dim.declsize,&dimid); if(ncstat != NC_NOERR) { THROWCHK(ncstat); goto done; } nullfree(definename); dim->ncid = dimid; } /* Make all duplicate dims have same dimid as basedim*/ /* (see computecdfdimnames)*/ for(i=0;i<nclistlength(dimset);i++) { CDFnode* dim = (CDFnode*)nclistget(dimset,i); if(dim->dim.basedim != NULL) { dim->ncid = dim->dim.basedim->ncid; } } done: nclistfree(dimset); return THROW(ncstat); }
/* Make the in-memory NC structure from reading the file header */ int nc_get_NC(NC3_INFO* ncp) { int status; v1hs gs; /* the get stream */ assert(ncp != NULL); /* Initialize stream gs */ gs.nciop = ncp->nciop; gs.offset = 0; /* beginning of file */ gs.extent = 0; gs.flags = 0; gs.version = 0; gs.base = NULL; gs.pos = gs.base; { /* * Come up with a reasonable stream read size. */ off_t filesize; size_t extent = ncp->xsz; if(extent <= ((fIsSet(ncp->flags, NC_64BIT_DATA))?MIN_NC5_XSZ:MIN_NC3_XSZ)) { status = ncio_filesize(ncp->nciop, &filesize); if(status) return status; if(filesize < sizeof(ncmagic)) { /* too small, not netcdf */ status = NC_ENOTNC; return status; } /* first time read */ extent = ncp->chunk; /* Protection for when ncp->chunk is huge; * no need to read hugely. */ if(extent > 4096) extent = 4096; if(extent > filesize) extent = filesize; } else if(extent > ncp->chunk) extent = ncp->chunk; /* * Invalidate the I/O buffers to force a read of the header * region. */ status = ncio_sync(gs.nciop); if(status) return status; status = fault_v1hs(&gs, extent); if(status) return status; } /* get the header from the stream gs */ { /* Get & check magic number */ schar magic[sizeof(ncmagic)]; (void) memset(magic, 0, sizeof(magic)); status = ncx_getn_schar_schar( (const void **)(&gs.pos), sizeof(magic), magic); if(status != ENOERR) goto unwind_get; if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0) { status = NC_ENOTNC; goto unwind_get; } /* Check version number in last byte of magic */ if (magic[sizeof(ncmagic)-1] == 0x1) { gs.version = 1; } else if (magic[sizeof(ncmagic)-1] == 0x2) { gs.version = 2; fSet(ncp->flags, NC_64BIT_OFFSET); /* Now we support version 2 file access on non-LFS systems -- rkr */ #if 0 if (sizeof(off_t) != 8) { fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n"); } #endif } else if (magic[sizeof(ncmagic)-1] == 0x5) { gs.version = 5; fSet(ncp->flags, NC_64BIT_DATA); } else { status = NC_ENOTNC; goto unwind_get; } } { size_t nrecs = 0; if (gs.version == 5) { long long tmp = 0; status = ncx_get_int64((const void **)(&gs.pos), &tmp); nrecs = (size_t)tmp; } else status = ncx_get_size_t((const void **)(&gs.pos), &nrecs); if(status != ENOERR) goto unwind_get; NC_set_numrecs(ncp, nrecs); } assert((char *)gs.pos < (char *)gs.end); status = v1h_get_NC_dimarray(&gs, &ncp->dims); if(status != ENOERR) goto unwind_get; status = v1h_get_NC_attrarray(&gs, &ncp->attrs); if(status != ENOERR) goto unwind_get; status = v1h_get_NC_vararray(&gs, &ncp->vars); if(status != ENOERR) goto unwind_get; ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8); status = NC_computeshapes(ncp); if(status != ENOERR) goto unwind_get; unwind_get: (void) rel_v1hs(&gs); return status; }
/* * 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 ncp->recsize += (*vpp)->len; last = (*vpp); } /* * for special case of exactly one record variable, pack value */ if(last != NULL && ncp->recsize == last->len) ncp->recsize = *last->dsizes * last->xsz; if(NC_IsNew(ncp)) NC_set_numrecs(ncp, 0); return NC_NOERR; }
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); }