/********************************************************************* * Copyright 1993, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Header$ *********************************************************************/ #include "ncdap3.h" #include "dapodom.h" #include "dapdump.h" /* Return 1 if we can reuse cached data to address the current get_vara request; return 0 otherwise. Target is in the constrained tree space. Currently, if the target matches a cache that is not a whole variable, then match is false. */ int iscached(NCDAPCOMMON* nccomm, CDFnode* target, NCcachenode** cachenodep) { int i,j,found,index; NCcache* cache; NCcachenode* cachenode; found = 0; if(target == NULL) goto done; /* Match the target variable against the prefetch, if any */ /* Note that prefetches are always whole variable */ cache = nccomm->cdf.cache; cachenode = cache->prefetch; if(cachenode!= NULL) { for(found=0,i=0;ivars);i++) { CDFnode* var = (CDFnode*)nclistget(cachenode->vars,i); if(var == target) { if(cachenodep) *cachenodep = cachenode; found=1; goto done; } } } /*search other cache nodes starting at latest first */ index = 0; for(i=nclistlength(cache->nodes)-1;i>=0;i--) { cachenode = (NCcachenode*)nclistget(cache->nodes,i); /* We currently do not try to match constraints; If the cachenode is constrained, then skip it */ if(!cachenode->wholevariable) continue; for(found=0,j=0;jvars);j++) { CDFnode* var = (CDFnode*)nclistget(cachenode->vars,j); if(var == target) {found=1;index=i;break;} } if(found) break; } if(found) { ASSERT((cachenode != NULL)); if(nclistlength(cache->nodes) > 1) { /* Manage the cache nodes as LRU */ nclistremove(cache->nodes,index); nclistpush(cache->nodes,(ncelem)cachenode); } if(cachenodep) *cachenodep = cachenode; } done: #ifdef DEBUG fprintf(stderr,"iscached: search: %s\n",makesimplepathstring3(target)); if(found) fprintf(stderr,"iscached: found: %s\n",dumpcachenode(cachenode)); else fprintf(stderr,"iscached: notfound\n"); #endif return found; } /* Compute the set of prefetched data; note that even if caching is off, we will still prefetch the small variables. */ NCerror prefetchdata3(NCDAPCOMMON* nccomm) { int i,j; NCerror ncstat = NC_NOERR; NClist* allvars = nccomm->cdf.varnodes; DCEconstraint* constraint = nccomm->oc.dapconstraint; NClist* vars = nclistnew(); NCcachenode* cache = NULL; DCEconstraint* newconstraint = NULL; /* Check if we can do constraints */ if(FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) { /*cannot constrain*/ /* If we cannot constrain, then pull in everything */ for(i=0;inctype == NC_Sequence || dapinsequence(var)) continue; /* Compute the # of elements in the variable */ for(j=0;jarray.dimensions);j++) { CDFnode* dim = (CDFnode*)nclistget(var->array.dimensions,j); nelems *= dim->dim.declsize; } if(nelems <= nccomm->cdf.smallsizelimit) nclistpush(vars,(ncelem)var); } } /* If there are no vars, then do nothing */ if(nclistlength(vars) == 0) { nccomm->cdf.cache->prefetch = NULL; goto done; } newconstraint = (DCEconstraint*)dceclone((DCEnode*)constraint); /* Construct the projections for this set of vars */ /* Initially, the constraints are same as the merged constraints */ restrictprojection34(vars,newconstraint->projections); /* similar for selections */ /* Currently do nothing */ ncstat = buildcachenode34(nccomm,newconstraint,vars,&cache,1); if(ncstat) goto done; newconstraint = NULL; /* buildcachenode34 takes control of newconstraint */ cache->wholevariable = 1; /* All prefetches are whole variable */ if(FLAGSET(nccomm->controls,NCF_SHOWFETCH)) { nclog(NCLOGNOTE,"prefetch."); } #ifdef DEBUG /* Log the set of prefetch variables */ NCbytes* buf = ncbytesnew(); ncbytescat(buf,"prefetch.vars: "); for(i=0;icdf.cache->prefetch = cache; done: nclistfree(vars); dcefree((DCEnode*)newconstraint); if(ncstat) freenccachenode(nccomm,cache); return THROW(ncstat); } NCerror buildcachenode34(NCDAPCOMMON* nccomm, DCEconstraint* constraint, NClist* varlist, NCcachenode** cachep, int isprefetch) { NCerror ncstat = NC_NOERR; OCerror ocstat = OC_NOERR; OCconnection conn = nccomm->oc.conn; OCobject ocroot = OCNULL; CDFnode* dxdroot = NULL; NCcachenode* cachenode = NULL; char* ce = NULL; if(FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) ce = NULL; else ce = buildconstraintstring3(constraint); ocstat = dap_oc_fetch(nccomm,conn,ce,OCDATADDS,&ocroot); nullfree(ce); if(ocstat) {THROWCHK(ocerrtoncerr(ocstat)); goto done;} ncstat = buildcdftree34(nccomm,ocroot,OCDATA,&dxdroot); if(ncstat) {THROWCHK(ncstat); goto done;} /* regrid */ if(!FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) { ncstat = regrid3(dxdroot,nccomm->cdf.ddsroot,constraint->projections); if(ncstat) {THROWCHK(ncstat); goto done;} } /* create the cache node */ cachenode = createnccachenode(); cachenode->prefetch = isprefetch; cachenode->vars = nclistclone(varlist); cachenode->datadds = dxdroot; cachenode->constraint = constraint; cachenode->wholevariable = iswholeconstraint(cachenode->constraint); /* save the root content*/ cachenode->ocroot = ocroot; cachenode->content = oc_data_new(conn); ocstat = oc_data_root(conn,ocroot,cachenode->content); if(ocstat) {THROWCHK(ocerrtoncerr(ocstat)); goto done;} /* capture the packet size */ ocstat = oc_raw_xdrsize(conn,ocroot,&cachenode->xdrsize); if(ocstat) {THROWCHK(ocerrtoncerr(ocstat)); goto done;} #ifdef DEBUG fprintf(stderr,"buildcachenode: new cache node: %s\n", dumpcachenode(cachenode)); #endif /* Insert into the cache. If not caching, then remove any previous cache node */ if(!isprefetch) { NCcache* cache = nccomm->cdf.cache; if(cache->nodes == NULL) cache->nodes = nclistnew(); /* remove cache nodes to get below the max cache size */ while(cache->cachesize + cachenode->xdrsize > cache->cachelimit) { NCcachenode* node = (NCcachenode*)nclistremove(cache->nodes,0); #ifdef DEBUG fprintf(stderr,"buildcachenode: purge cache node: %s\n", dumpcachenode(cachenode)); #endif cache->cachesize -= node->xdrsize; freenccachenode(nccomm,node); } /* Remove cache nodes to get below the max cache count */ /* If not caching, then cachecount should be 0 */ while(nclistlength(cache->nodes) > cache->cachecount) { NCcachenode* node = (NCcachenode*)nclistremove(cache->nodes,0); #ifdef DEBUG fprintf(stderr,"buildcachenode: count purge cache node: %s\n", dumpcachenode(node)); #endif cache->cachesize -= node->xdrsize; freenccachenode(nccomm,node); } nclistpush(nccomm->cdf.cache->nodes,(ncelem)cachenode); cache->cachesize += cachenode->xdrsize; } #ifdef DEBUG fprintf(stderr,"buildcachenode: %s\n",dumpcachenode(cachenode)); #endif done: if(cachep) *cachep = cachenode; if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); if(ncstat) { freecdfroot34(dxdroot); freenccachenode(nccomm,cachenode); } return THROW(ncstat); } NCcachenode* createnccachenode(void) { NCcachenode* mem = (NCcachenode*)calloc(1,sizeof(NCcachenode)); return mem; } void freenccachenode(NCDAPCOMMON* nccomm, NCcachenode* node) { if(node == NULL) return; oc_data_free(nccomm->oc.conn,node->content); oc_data_free(nccomm->oc.conn,node->content); dcefree((DCEnode*)node->constraint); freecdfroot34(node->datadds); nclistfree(node->vars); nullfree(node); } void freenccache(NCDAPCOMMON* nccomm, NCcache* cache) { int i; if(cache == NULL) return; freenccachenode(nccomm,cache->prefetch); for(i=0;inodes);i++) { freenccachenode(nccomm,(NCcachenode*)nclistget(cache->nodes,i)); } nclistfree(cache->nodes); nullfree(cache); } NCcache* createnccache(void) { NCcache* c = (NCcache*)calloc(1,sizeof(NCcache)); c->cachelimit = DFALTCACHELIMIT; c->cachesize = 0; c->nodes = nclistnew(); c->cachecount = DFALTCACHECOUNT; return c; }