/* Extract data for a netcdf variable that has a string dimension. */ static int extractstring( NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xnode, DCEsegment* segment, size_t dimindex, /*notused*/ OClink conn, OCdatanode currentcontent, struct NCMEMORY* memory ) { NCerror ncstat = NC_NOERR; OCerror ocstat = OC_NOERR; int i; size_t rank0; NClist* strings = NULL; Dapodometer* odom = NULL; ASSERT(xnode->etype == NC_STRING || xnode->etype == NC_URL); /* Compute rank minus string dimension */ rank0 = nclistlength(xnode->array.dimset0); /* keep whole extracted strings stored in an NClist */ strings = nclistnew(); if(rank0 == 0) {/*=> scalar*/ char* value = NULL; ocstat = oc_data_readscalar(conn,currentcontent,sizeof(value),&value); if(ocstat != OC_NOERR) goto done; nclistpush(strings,(void*)value); } else { /* Use the odometer to walk to the appropriate fields*/ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char* value = NULL; ocstat = oc_data_readn(conn,currentcontent,odom->index,1,sizeof(value),&value); if(ocstat != OC_NOERR) goto done; nclistpush(strings,(void*)value); dapodom_next(odom); } dapodom_free(odom); } /* Get each string in turn, slice it by applying the string dimm and store in user supplied memory */ for(i=0;i<nclistlength(strings);i++) { char* s = (char*)nclistget(strings,i); slicestring(conn,s,&segment->slices[rank0],memory); free(s); } nclistfree(strings); done: if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); return THROW(ncstat); }
/* We are at a primitive variable or scalar that has no string dimensions. Extract the data. (This is way too complicated) */ static int extract( NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xnode, DCEsegment* segment, size_t dimindex,/*notused*/ OClink conn, OCdatanode currentcontent, struct NCMEMORY* memory ) { OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; size_t count,rank0; Dapodometer* odom = NULL; size_t externtypesize; size_t interntypesize; int requireconversion; char value[16]; ASSERT((segment != NULL)); requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype); ASSERT(xgetvar->cache != NULL); externtypesize = nctypesizeof(xgetvar->dsttype); interntypesize = nctypesizeof(xnode->etype); rank0 = nclistlength(xnode->array.dimset0); #ifdef DEBUG2 fprintf(stderr,"moveto: primitive: segment=%s", dcetostring((DCEnode*)segment)); fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable); fprintf(stderr,"\n"); #endif if(rank0 == 0) {/* scalar */ char* mem = (requireconversion?value:memory->next); ASSERT(externtypesize <= sizeof(value)); /* Read the whole scalar directly into memory */ ocstat = oc_data_readscalar(conn,currentcontent,externtypesize,mem); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} if(requireconversion) { /* convert the value to external type */ ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } memory->next += (externtypesize); } else if(xgetvar->cache->wholevariable) {/* && rank0 > 0 */ /* There are multiple cases, assuming no conversion required. 1) client is asking for whole variable => start=0, count=totalsize, stride=1 => read whole thing at one shot 2) client is asking for non-strided subset and edges are maximal => start=x, count=y, stride=1 => read whole subset at one shot 3) client is asking for strided subset or edges are not maximal => start=x, count=y, stride=s => we have to use odometer on leading prefix. If conversion required, then read one-by-one */ int safeindex = dcesafeindex(segment,0,rank0); assert(safeindex >= 0 && safeindex <= rank0); if(!requireconversion && safeindex == 0) { /* can read whole thing */ size_t internlen; count = dcesegmentsize(segment,0,rank0); /* how many to read */ internlen = interntypesize*count; /* Read the whole variable directly into memory.*/ ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next); /* bump memory pointer */ memory->next += internlen; if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } else if(!requireconversion && safeindex > 0 && safeindex < rank0) { size_t internlen; /* We need to build an odometer for the unsafe prefix of the slices */ odom = dapodom_fromsegment(segment,0,safeindex); count = dcesegmentsize(segment,safeindex,rank0); /* read in count chunks */ internlen = interntypesize*count; while(dapodom_more(odom)) { ocstat = oc_data_readn(conn,currentcontent,odom->index,count,internlen,memory->next); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} memory->next += internlen; dapodom_next(odom); } dapodom_free(odom); } else { /* Cover following cases, all of which require reading values one-by-one: 1. requireconversion 2. !requireconversion but safeindex == rank0 =>no safe indices Note that in case 2, we will do a no-op conversion. */ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char value[16]; /* Big enough to hold any numeric value */ ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} memory->next += (externtypesize); dapodom_next(odom); } dapodom_free(odom); } } else { /* !xgetvar->cache->wholevariable && rank0 > 0 */ /* This is the case where the constraint was applied by the server, so we just read it in, possibly with conversion */ if(requireconversion) { /* read one-by-one */ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char value[16]; /* Big enough to hold any numeric value */ ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} memory->next += (externtypesize); dapodom_next(odom); } dapodom_free(odom); } else {/* Read straight to memory */ size_t internlen; count = dcesegmentsize(segment,0,rank0); /* how many to read */ internlen = interntypesize*count; ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } } done: return THROW(ncstat); }
int nc3d_getvarmx(int ncid, int varid, const size_t *start, const size_t *edges, const ptrdiff_t* stride, const ptrdiff_t* map, void* data, nc_type dsttype0) { NCerror ncstat = NC_NOERR; int i; NC* drno; NC* substrate; NC3_INFO* substrate3; NCDAPCOMMON* dapcomm; NC_var* var; CDFnode* cdfvar; /* cdf node mapping to var*/ NClist* varnodes; nc_type dsttype; size_t externsize; size_t dimsizes[NC_MAX_VAR_DIMS]; Dapodometer* odom = NULL; unsigned int ncrank; NClist* ncdims = NULL; size_t nelems; #ifdef NEWVARM char* localcopy; /* of whole variable */ #endif ncstat = NC_check_id(ncid, (NC**)&drno); if(ncstat != NC_NOERR) goto done; dapcomm = (NCDAPCOMMON*)drno->dispatchdata; ncstat = NC_check_id(drno->substrate, &substrate); if(ncstat != NC_NOERR) goto done; substrate3 = (NC3_INFO*)drno->dispatchdata; var = NC_lookupvar(substrate3,varid); if(var == NULL) {ncstat = NC_ENOTVAR; goto done;} /* Locate var node via varid */ varnodes = dapcomm->cdf.ddsroot->tree->varnodes; for(i=0;i<nclistlength(varnodes);i++) { CDFnode* node = (CDFnode*)nclistget(varnodes,i); if(node->array.basevar == NULL && node->nctype == NC_Atomic && node->ncid == varid) { cdfvar = node; break; } } ASSERT((cdfvar != NULL)); ASSERT((strcmp(cdfvar->ncfullname,var->name->cp)==0)); if(nclistlength(cdfvar->array.dimsetplus) == 0) { /* The variable is a scalar; consequently, there is only one thing to get and only one place to put it. */ /* recurse with additional parameters */ return THROW(nc3d_getvarx(ncid,varid, NULL,NULL,NULL, data,dsttype0)); } dsttype = (dsttype0); /* Default to using the inquiry type for this var*/ if(dsttype == NC_NAT) dsttype = cdfvar->externaltype; /* Validate any implied type conversion*/ if(cdfvar->etype != dsttype && dsttype == NC_CHAR) { /* The only disallowed conversion is to/from char and non-byte numeric types*/ switch (cdfvar->etype) { case NC_STRING: case NC_URL: case NC_CHAR: case NC_BYTE: case NC_UBYTE: break; default: return THROW(NC_ECHAR); } } externsize = nctypesizeof(dsttype); /* Accumulate the dimension sizes and the total # of elements */ ncdims = cdfvar->array.dimsetall; ncrank = nclistlength(ncdims); nelems = 1; /* also Compute the number of elements being retrieved */ for(i=0;i<ncrank;i++) { CDFnode* dim = (CDFnode*)nclistget(ncdims,i); dimsizes[i] = dim->dim.declsize; nelems *= edges[i]; } /* Originally, this code repeatedly extracted single values using get_var1. In an attempt to improve performance, I have converted to reading the whole variable at once and walking it locally. */ #ifdef NEWVARM localcopy = (char*)malloc(nelems*externsize); /* We need to use the varieties of get_vars in order to properly do conversion to the external type */ switch (dsttype) { case NC_CHAR: ncstat = nc_get_vars_text(ncid,varid,start, edges, stride, (char*)localcopy); break; case NC_BYTE: ncstat = nc_get_vars_schar(ncid,varid,start, edges, stride, (signed char*)localcopy); break; case NC_SHORT: ncstat = nc_get_vars_short(ncid,varid, start, edges, stride, (short*)localcopy); break; case NC_INT: ncstat = nc_get_vars_int(ncid,varid,start, edges, stride, (int*)localcopy); break; case NC_FLOAT: ncstat = nc_get_vars_float(ncid,varid,start, edges, stride, (float*)localcopy); break; case NC_DOUBLE: ncstat = nc_get_vars_double(ncid,varid, start, edges, stride, (double*)localcopy); break; default: break; } odom = dapodom_new(ncrank,start,edges,stride,NULL); /* Walk the local copy */ for(i=0;i<nelems;i++) { size_t voffset = dapodom_varmcount(odom,map,dimsizes); void* dataoffset = (void*)(((char*)data) + (externsize*voffset)); char* localpos = (localcopy + externsize*i); /* extract the indexset'th value from local copy */ memcpy(dataoffset,(void*)localpos,externsize); /* fprintf(stderr,"new: %lu -> %lu %f\n", (unsigned long)(i), (unsigned long)voffset, *(float*)localpos); */ dapodom_next(odom); } #else odom = dapodom_new(ncrank,start,edges,stride,NULL); while(dapodom_more(odom)) { size_t* indexset = odom->index; size_t voffset = dapodom_varmcount(odom,map,dimsizes); char internalmem[128]; char externalmem[128]; void* dataoffset = (void*)(((char*)data) + (externsize*voffset)); /* get the indexset'th value using variable's internal type */ ncstat = nc_get_var1(ncid,varid,indexset,(void*)&internalmem); if(ncstat != NC_NOERR) goto done; /* Convert to external type */ ncstat = dapconvert3(cdfvar->etype,dsttype,externalmem,internalmem); if(ncstat != NC_NOERR) goto done; memcpy(dataoffset,(void*)externalmem,externsize); /* fprintf(stderr,"old: %lu -> %lu %f\n", (unsigned long)dapodom_count(odom), (unsigned long)voffset, *(float*)externalmem); */ dapodom_next(odom); } #endif done: return ncstat; }
static NCerror movetor(NCDAPCOMMON* nccomm, OCdatanode currentcontent, NClist* path, int depth, /* depth is position in segment list*/ Getvara* xgetvar, size_t dimindex, /* dimindex is position in xgetvar->slices*/ struct NCMEMORY* memory, NClist* segments) { OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; OClink conn = nccomm->oc.conn; CDFnode* xnode = (CDFnode*)nclistget(path,depth); OCdatanode reccontent = NULL; OCdatanode dimcontent = NULL; OCdatanode fieldcontent = NULL; Dapodometer* odom = NULL; int hasstringdim = 0; DCEsegment* segment; OCDT mode; /* Note that we use depth-1 because the path contains the DATASET but the segment list does not */ segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/ if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1; /* Get the mode */ mode = oc_data_mode(conn,currentcontent); #ifdef DEBUG2 fprintf(stderr,"moveto: nctype=%d depth=%d dimindex=%d mode=%s", xnode->nctype, depth,dimindex,oc_data_modestring(mode)); fprintf(stderr," segment=%s hasstringdim=%d\n", dcetostring((DCEnode*)segment),hasstringdim); #endif switch (xnode->nctype) { #if 0 #define OCDT_FIELD ((OCDT)(1)) /* field of a container */ #define OCDT_ELEMENT ((OCDT)(2)) /* element of a structure array */ #define OCDT_RECORD ((OCDT)(4)) /* record of a sequence */ #define OCDT_ARRAY ((OCDT)(8)) /* is structure array */ #define OCDT_SEQUENCE ((OCDT)(16)) /* is sequence */ #define OCDT_ATOMIC ((OCDT)(32)) /* is atomic leaf */ #endif default: goto done; case NC_Grid: case NC_Dataset: case NC_Structure: /* Separate out the case where structure is dimensioned */ if(oc_data_indexable(conn,currentcontent)) { /* => dimensioned structure */ /* The current segment should reflect the proper parts of the nc_get_vara argument */ /* Create odometer for this structure's part of the projection */ odom = dapodom_fromsegment(segment,0,segment->rank); while(dapodom_more(odom)) { /* Compute which instance to move to*/ ocstat = oc_data_ithelement(conn,currentcontent, odom->index,&dimcontent); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ASSERT(oc_data_indexed(conn,dimcontent)); ncstat = movetor(nccomm,dimcontent, path,depth,/*keep same depth*/ xgetvar,dimindex+segment->rank, memory,segments); dapodom_next(odom); } dapodom_free(odom); } else {/* scalar instance */ ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } break; case NC_Sequence: if(fIsSet(mode,OCDT_SEQUENCE)) { ASSERT((xnode->attachment != NULL)); ASSERT((segment != NULL)); ASSERT((segment->rank == 1)); /* Build an odometer for walking the sequence, however, watch out for the case when the user set a limit and that limit is not actually reached in this request. */ /* By construction, this sequence represents the first (and only) dimension of this segment */ odom = dapodom_fromsegment(segment,0,1); while(dapodom_more(odom)) { size_t recordindex = dapodom_count(odom); ocstat = oc_data_ithrecord(conn,currentcontent, recordindex,&reccontent); if(ocstat != OC_NOERR) { if(ocstat == OC_EINDEX) ocstat = OC_EINVALCOORDS; THROWCHK(ocstat); goto done; } ncstat = movetor(nccomm,reccontent, path,depth, xgetvar,dimindex+1, memory,segments); if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto done;} dapodom_next(odom); } } else if(fIsSet(mode,OCDT_RECORD)) { /* Treat like structure */ /* currentcontent points to the record instance */ ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } break; case NC_Atomic: if(hasstringdim) ncstat = extractstring(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory); else ncstat = extract(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory); break; } done: oc_data_free(conn,dimcontent); oc_data_free(conn,fieldcontent); oc_data_free(conn,reccontent); if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); return THROW(ncstat); }