int dapshiftprojection(DCEprojection* projection) { int ncstat = NC_NOERR; int i,j; NClist* segments; #ifdef DEBUG1 fprintf(stderr,"dapshiftprojection.before: %s\n",dumpprojection(projection)); #endif ASSERT(projection->discrim == CES_VAR); segments = projection->var->segments; for(i=0;i<nclistlength(segments);i++) { DCEsegment* seg = (DCEsegment*)nclistget(segments,i); for(j=0;j<seg->rank;j++) { DCEslice* slice = seg->slices+j; dapshiftslice(slice); } } #ifdef DEBUG1 fprintf(stderr,"dapshiftprojection.after: %s\n",dumpprojection(projection)); #endif return ncstat; }
/* Given the arguments to vara construct a corresponding projection with any pseudo dimensions removed */ NCerror buildvaraprojection3(Getvara* getvar, const size_t* startp, const size_t* countp, const ptrdiff_t* stridep, DCEprojection** projectionp) { int i,j; NCerror ncstat = NC_NOERR; CDFnode* var = getvar->target; DCEprojection* projection = NULL; NClist* path = nclistnew(); NClist* segments = NULL; int dimindex; ncstat = dapvar2projection(var,&projection); #ifdef DEBUG fprintf(stderr,"buildvaraprojection: %s\n",dumpprojection(projection)); #endif /* We need to assign the start/count/stride info to each segment; declsize will have been set */ segments = projection->var->segments; dimindex = 0; for(i=0;i<nclistlength(segments);i++) { DCEsegment* segment = (DCEsegment*)nclistget(segments,i); for(j=0;j<segment->rank;j++) { DCEslice* slice = &segment->slices[j]; /* make each slice represent the corresponding start/count/stride */ slice->first = startp[dimindex+j]; slice->stride = stridep[dimindex+j]; slice->count = countp[dimindex+j]; slice->length = slice->count * slice->stride; if(slice->length > slice->declsize) slice->length = slice->declsize; slice->stop = (slice->first + slice->length); if(slice->stop > slice->declsize) slice->stop = slice->declsize; } dimindex += segment->rank; } #ifdef DEBUG fprintf(stderr,"buildvaraprojection.final: %s\n",dumpprojection(projection)); #endif #ifdef IGNORE removepseudodims3(projection); #endif #ifdef DEBUG fprintf(stderr,"buildvaraprojection3: projection=%s\n", dumpprojection(projection)); #endif if(projectionp) *projectionp = projection; nclistfree(path); if(ncstat) dcefree((DCEnode*)projection); return ncstat; }
/* Given a set of projections and a projection representing a variable (from, say vara or prefetch) construct a single projection for fetching that variable with the proper constraints. */ int daprestrictprojection(NClist* projections, DCEprojection* var, DCEprojection** resultp) { int ncstat = NC_NOERR; int i; DCEprojection* result = NULL; #ifdef DEBUG1 fprintf(stderr,"restrictprojection.before: constraints=|%s| vara=|%s|\n", dumpprojections(projections), dumpprojection(var)); #endif ASSERT(var != NULL); /* the projection list will contain at most 1 match for the var by construction */ for(result=null,i=0;i<nclistlength(projections);i++) { DCEprojection* p1 = (DCEprojection*)nclistget(projections,i); if(p1 == NULL || p1->discrim != CES_VAR) continue; if(p1->var->annotation == var->var->annotation) { result = p1; break; } } if(result == NULL) { result = (DCEprojection*)dceclone((DCEnode*)var); /* use only the var projection */ goto done; } result = (DCEprojection*)dceclone((DCEnode*)result); /* so we can modify */ #ifdef DEBUG1 fprintf(stderr,"restrictprojection.choice: base=|%s| add=|%s|\n", dumpprojection(result),dumpprojection(var)); #endif /* We need to merge the projection from the projection list with the var projection */ ncstat = dcemergeprojections(result,var); /* result will be modified */ done: if(resultp) *resultp = result; #ifdef DEBUG fprintf(stderr,"restrictprojection.after=|%s|\n", dumpprojection(result)); #endif return ncstat; }
/* Convert a CDFnode var to a projection; include pseudodimensions; always whole variable. */ int dapvar2projection(CDFnode* var, DCEprojection** projectionp) { int i,j; int ncstat = NC_NOERR; NClist* path = nclistnew(); NClist* segments; DCEprojection* projection = NULL; int dimindex; /* Collect the nodes needed to construct the projection segment */ collectnodepath3(var,path,!WITHDATASET); segments = nclistnew(); dimindex = 0; /* point to next subset of slices */ nclistsetalloc(segments,nclistlength(path)); for(i=0;i<nclistlength(path);i++) { DCEsegment* segment = (DCEsegment*)dcecreate(CES_SEGMENT); CDFnode* n = (CDFnode*)nclistget(path,i); int localrank; NClist* dimset; segment->annotation = (void*)n; segment->name = nulldup(n->ocname); /* We need to assign whole slices to each segment */ localrank = nclistlength(n->array.dimsetplus); segment->rank = localrank; dimset = n->array.dimsetplus; for(j=0;j<localrank;j++) { DCEslice* slice; CDFnode* dim; slice = &segment->slices[j]; dim = (CDFnode*)nclistget(dimset,j); ASSERT(dim->dim.declsize0 > 0); dcemakewholeslice(slice,dim->dim.declsize0); } segment->slicesdefined = 1; segment->slicesdeclized = 1; dimindex += localrank; nclistpush(segments,(ncelem)segment); } projection = (DCEprojection*)dcecreate(CES_PROJECT); projection->discrim = CES_VAR; projection->var = (DCEvar*)dcecreate(CES_VAR); projection->var->annotation = (void*)var; projection->var->segments = segments; #ifdef DEBUG1 fprintf(stderr,"dapvar2projection: projection=%s\n", dumpprojection(projection)); #endif nclistfree(path); if(ncstat) dcefree((DCEnode*)projection); else if(projectionp) *projectionp = projection; return ncstat; }
/* Remove any pseudodimensions (sequence and string)*/ static NCerror removepseudodims(DCEprojection* proj) { int i; #ifdef DEBUG1 fprintf(stderr,"removesequencedims.before: %s\n",dumpprojection(proj)); #endif for(i=0;i<nclistlength(proj->var->segments);i++) { DCEsegment* seg = (DCEsegment*)nclistget(proj->var->segments,i); CDFnode* cdfnode = (CDFnode*)seg->annotation; if(cdfnode->array.seqdim != NULL) seg->rank = 0; else if(cdfnode->array.stringdim != NULL) seg->rank--; } #ifdef DEBUG1 fprintf(stderr,"removepseudodims.after: %s\n",dumpprojection(proj)); #endif return NC_NOERR; }
/* Make sure that the slice declsizes are all defined for this projection */ static NCerror qualifyprojectionsizes3(DCEprojection* proj) { int i,j; ASSERT(proj->discrim == CES_VAR); #ifdef DEBUG fprintf(stderr,"qualifyprojectionsizes.before: %s\n", dumpprojection(proj)); #endif for(i=0;i<nclistlength(proj->var->segments);i++) { DCEsegment* seg = (DCEsegment*)nclistget(proj->var->segments,i); NClist* dimset = NULL; CDFnode* cdfnode = (CDFnode*)seg->annotation; ASSERT(cdfnode != NULL); dimset = cdfnode->array.dimsetplus; seg->rank = nclistlength(dimset); /* For this, we do not want any string dimensions */ if(cdfnode->array.stringdim != NULL) seg->rank--; for(j=0;j<seg->rank;j++) { CDFnode* dim = (CDFnode*)nclistget(dimset,j); if(dim->dim.basedim != NULL) dim = dim->dim.basedim; ASSERT(dim != null); if(seg->slicesdefined) seg->slices[j].declsize = dim->dim.declsize; else dcemakewholeslice(seg->slices+j,dim->dim.declsize); } seg->slicesdefined = 1; seg->slicesdeclized = 1; } #ifdef DEBUG fprintf(stderr,"qualifyprojectionsizes.after: %s\n", dumpprojection(proj)); #endif return NC_NOERR; }
/* convert all names in projections in paths to be fully qualified by adding prefix segment objects. */ static NCerror qualifyprojectionnames3(DCEprojection* proj) { NCerror ncstat = NC_NOERR; NClist* fullpath = nclistnew(); ASSERT((proj->discrim == CES_VAR && proj->var->annotation != NULL && ((CDFnode*)proj->var->annotation)->ocnode != OCNULL)); collectnodepath3((CDFnode*)proj->var->annotation,fullpath,!WITHDATASET); #ifdef DEBUG fprintf(stderr,"qualify: %s -> ", dumpprojection(proj)); #endif /* Now add path nodes to create full path */ completesegments3(fullpath,proj->var->segments); #ifdef DEBUG fprintf(stderr,"%s\n", dumpprojection(proj)); #endif nclistfree(fullpath); return ncstat; }
/* Convert an NCprojection instance into a string that can be used with the url */ char* dumpprojections(NClist* projections) { int i; NCbytes* buf = ncbytesnew(); char* pstring; for(i=0;i<nclistlength(projections);i++) { NCprojection* p = (NCprojection*)nclistget(projections,i); if(i > 0) ncbytescat(buf,","); ncbytescat(buf,dumpprojection(p)); } pstring = ncbytesdup(buf); ncbytesfree(buf); return pstring; }
NCerror nc3d_getvarx(int ncid, int varid, const size_t *startp, const size_t *countp, const ptrdiff_t* stridep, void *data, nc_type dsttype0) { NCerror ncstat = NC_NOERR; OCerror ocstat = OC_NOERR; int i; NC* drno; NC* substrate; NCDAPCOMMON* dapcomm; CDFnode* cdfvar = NULL; /* cdf node mapping to var*/ NClist* varnodes; nc_type dsttype; Getvara* varainfo = NULL; CDFnode* xtarget = NULL; /* target in DATADDS */ CDFnode* target = NULL; /* target in constrained DDS */ DCEprojection* varaprojection = NULL; NCcachenode* cachenode = NULL; size_t localcount[NC_MAX_VAR_DIMS]; NClist* ncdimsall; size_t ncrank; NClist* vars = NULL; DCEconstraint* fetchconstraint = NULL; DCEprojection* fetchprojection = NULL; DCEprojection* walkprojection = NULL; int state; #define FETCHWHOLE 1 /* fetch whole data set */ #define FETCHVAR 2 /* fetch whole variable */ #define FETCHPART 4 /* fetch constrained variable */ #define CACHED 8 /* whole variable is already in the cache */ ncstat = NC_check_id(ncid, (NC**)&drno); if(ncstat != NC_NOERR) goto fail; dapcomm = (NCDAPCOMMON*)drno->dispatchdata; ncstat = NC_check_id(drno->substrate, (NC**)&substrate); if(ncstat != NC_NOERR) goto fail; /* 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)); /* If the variable is prefetchable, then now is the time to do a lazy prefetch */ if(FLAGSET(dapcomm->controls,NCF_PREFETCH) && !FLAGSET(dapcomm->controls,NCF_PREFETCH_EAGER)) { if(dapcomm->cdf.cache != NULL && dapcomm->cdf.cache->prefetch == NULL) { ncstat = prefetchdata3(dapcomm); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} } } /* Get the dimension info */ ncdimsall = cdfvar->array.dimsetall; ncrank = nclistlength(ncdimsall); #ifdef DEBUG { int i; fprintf(stderr,"getvarx: %s",cdfvar->ncfullname); for(i=0;i<ncrank;i++) fprintf(stderr,"(%ld:%ld:%ld)", (long)startp[i], (long)countp[i], (long)stridep[i] ); fprintf(stderr,"\n"); } #endif /* Fill in missing arguments */ if(startp == NULL) startp = nc_sizevector0; if(countp == NULL) { /* Accumulate the dimension sizes */ for(i=0;i<ncrank;i++) { CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i); localcount[i] = dim->dim.declsize; } countp = localcount; } if(stridep == NULL) stridep = nc_ptrdiffvector1; /* Validate the dimension sizes */ for(i=0;i<ncrank;i++) { CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i); if(startp[i] > dim->dim.declsize || startp[i]+countp[i] > dim->dim.declsize) { ncstat = NC_EINVALCOORDS; goto fail; } } #ifdef DEBUG { NClist* dims = cdfvar->array.dimsetall; fprintf(stderr,"getvarx: %s",cdfvar->ncfullname); if(nclistlength(dims) > 0) {int i; for(i=0;i<nclistlength(dims);i++) fprintf(stderr,"(%lu:%lu:%lu)",(unsigned long)startp[i],(unsigned long)countp[i],(unsigned long)stridep[i]); fprintf(stderr," -> "); for(i=0;i<nclistlength(dims);i++) if(stridep[i]==1) fprintf(stderr,"[%lu:%lu]",(unsigned long)startp[i],(unsigned long)((startp[i]+countp[i])-1)); else { unsigned long iend = (stridep[i] * countp[i]); iend = (iend + startp[i]); iend = (iend - 1); fprintf(stderr,"[%lu:%lu:%lu]", (unsigned long)startp[i],(unsigned long)stridep[i],iend); } } fprintf(stderr,"\n"); } #endif 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); } } ncstat = makegetvar34(dapcomm,cdfvar,data,dsttype,&varainfo); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} /* Compile the start/stop/stride info into a projection */ ncstat = buildvaraprojection3(varainfo->target, startp,countp,stridep, &varaprojection); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} fetchprojection = NULL; walkprojection = NULL; /* Create walkprojection as the merge of the url projections and the vara projection; may change in FETCHPART case below*/ ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections, varaprojection,&walkprojection); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} #ifdef DEBUG fprintf(stderr,"getvarx: walkprojection: |%s|\n",dumpprojection(walkprojection)); #endif /* define the var list of interest */ vars = nclistnew(); nclistpush(vars,(void*)varainfo->target); state = 0; if(iscached(dapcomm,cdfvar,&cachenode)) { /* ignores non-whole variable cache entries */ state = CACHED; ASSERT((cachenode != NULL)); #ifdef DEBUG fprintf(stderr,"var is in cache\n"); #endif /* If it is cached, then it is a whole variable but may still need to apply constraints during the walk */ ASSERT(cachenode->wholevariable); /* by construction */ } else if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) { state = FETCHWHOLE; } else {/* load using constraints */ if(FLAGSET(dapcomm->controls,NCF_WHOLEVAR)) state = FETCHVAR; else state = FETCHPART; } ASSERT(state != 0); switch (state) { case FETCHWHOLE: { /* buildcachenode3 will create a new cachenode and will also fetch the whole corresponding datadds. */ /* Build the complete constraint to use in the fetch */ fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); /* Use no projections or selections */ fetchconstraint->projections = nclistnew(); fetchconstraint->selections = nclistnew(); #ifdef DEBUG fprintf(stderr,"getvarx: FETCHWHOLE: fetchconstraint: %s\n",dumpconstraint(fetchconstraint)); #endif ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0); fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/ if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} } break; case CACHED: { } break; case FETCHVAR: { /* Fetch a complete single variable */ /* Create fetch projection as the merge of the url projections and the vara projection */ ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections, varaprojection,&fetchprojection); /* elide any sequence and string dimensions (dap servers do not allow such). */ ncstat = removepseudodims(fetchprojection); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} /* Convert to a whole variable projection */ dcemakewholeprojection(fetchprojection); #ifdef DEBUG fprintf(stderr,"getvarx: FETCHVAR: fetchprojection: |%s|\n",dumpprojection(fetchprojection)); #endif /* Build the complete constraint to use in the fetch */ fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); /* merged constraint just uses the url constraint selection */ fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections); /* and the created fetch projection */ fetchconstraint->projections = nclistnew(); nclistpush(fetchconstraint->projections,(void*)fetchprojection); #ifdef DEBUG fprintf(stderr,"getvarx: FETCHVAR: fetchconstraint: %s\n",dumpconstraint(fetchconstraint)); #endif /* buildcachenode3 will create a new cachenode and will also fetch the corresponding datadds. */ ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0); fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/ if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} } break; case FETCHPART: { /* Create fetch projection as the merge of the url projections and the vara projection */ ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections, varaprojection,&fetchprojection); /* elide any sequence and string dimensions (dap servers do not allow such). */ ncstat = removepseudodims(fetchprojection); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} /* Shift the varaprojection for simple walk */ dcefree((DCEnode*)walkprojection) ; /* reclaim any existing walkprojection */ walkprojection = (DCEprojection*)dceclone((DCEnode*)varaprojection); dapshiftprojection(walkprojection); #ifdef DEBUG fprintf(stderr,"getvarx: FETCHPART: fetchprojection: |%s|\n",dumpprojection(fetchprojection)); #endif /* Build the complete constraint to use in the fetch */ fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); /* merged constraint just uses the url constraint selection */ fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections); /* and the created fetch projection */ fetchconstraint->projections = nclistnew(); nclistpush(fetchconstraint->projections,(void*)fetchprojection); #ifdef DEBUG fprintf(stderr,"getvarx: FETCHPART: fetchconstraint: %s\n",dumpconstraint(fetchconstraint)); #endif /* buildcachenode3 will create a new cachenode and will also fetch the corresponding datadds. */ ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0); fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/ if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} } break; default: PANIC1("unknown fetch state: %d\n",state); } ASSERT(cachenode != NULL); #ifdef DEBUG fprintf(stderr,"cache.datadds=%s\n",dumptree(cachenode->datadds)); #endif /* attach DATADDS to (constrained) DDS */ unattach34(dapcomm->cdf.ddsroot); ncstat = attachsubset34(cachenode->datadds,dapcomm->cdf.ddsroot); if(ncstat) goto fail; /* Fix up varainfo to use the cache */ varainfo->cache = cachenode; cachenode = NULL; varainfo->varaprojection = walkprojection; walkprojection = NULL; /* Get the var correlate from the datadds */ target = varainfo->target; xtarget = target->attachment; if(xtarget == NULL) {THROWCHK(ncstat=NC_ENODATA); goto fail;} /* Switch to datadds tree space*/ varainfo->target = xtarget; save = (DCEnode*)varaprojection; ncstat = moveto(dapcomm,varainfo,varainfo->cache->datadds,data); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} nclistfree(vars); dcefree((DCEnode*)varaprojection); dcefree((DCEnode*)fetchconstraint); freegetvara(varainfo); fail: if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); return THROW(ncstat); }
/* Given the arguments to vara construct a corresponding projection with any pseudo dimensions removed */ NCerror buildvaraprojection(CDFnode* var, const size_t* startp, const size_t* countp, const ptrdiff_t* stridep, DCEprojection** projectionp) { int i,j; NCerror ncstat = NC_NOERR; DCEprojection* projection = NULL; NClist* path = nclistnew(); NClist* segments = NULL; int dimindex; /* Build a skeleton projection that has 1 segment for every cdfnode from root to the variable of interest. Each segment has the slices from its corresponding node in the path, including pseudo-dims */ ncstat = dapvar2projection(var,&projection); #ifdef DEBUG fprintf(stderr,"buildvaraprojection: skeleton: %s\n",dumpprojection(projection)); #endif /* Now, modify the projection to reflect the corresponding start/count/stride from the nc_get_vara arguments. */ segments = projection->var->segments; dimindex = 0; for(i=0;i<nclistlength(segments);i++) { DCEsegment* segment = (DCEsegment*)nclistget(segments,i); for(j=0;j<segment->rank;j++) { size_t count = 0; DCEslice* slice = &segment->slices[j]; /* make each slice represent the corresponding start/count/stride */ slice->first = startp[dimindex+j]; slice->stride = stridep[dimindex+j]; count = countp[dimindex+j]; slice->count = count; slice->length = count * slice->stride; slice->last = (slice->first + slice->length) - 1; if(slice->last >= slice->declsize) { slice->last = slice->declsize - 1; /* reverse compute the new length */ slice->length = (slice->last - slice->first) + 1; } } dimindex += segment->rank; } #ifdef DEBUG fprintf(stderr,"buildvaraprojection.final: %s\n",dumpprojection(projection)); #endif #ifdef DEBUG fprintf(stderr,"buildvaraprojection3: final: projection=%s\n", dumpprojection(projection)); #endif if(projectionp) *projectionp = projection; nclistfree(path); if(ncstat) dcefree((DCEnode*)projection); return ncstat; }