1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *********************************************************************/
5
6#include "ncdap.h"
7#include "dapdump.h"
8
9/*
10Grads servers always require a constraint,
11which does not necessarily happen during prefetch.
12So this flag controls this. By default, it is on.
13*/
14#define GRADS_PREFETCH
15
16static int iscacheableconstraint(DCEconstraintcon);
17
18/* Return 1 if we can reuse cached data to address
19   the current get_vara request; return 0 otherwise.
20   Target is in the constrained tree space.
21   Currently, if the target matches a cache that is not
22   a whole variable, then match is false.
23*/
24int
25iscached(NCDAPCOMMONnccommCDFnodetargetNCcachenode** cachenodep)
26{
27    int i,j,found,index;
28    NCcachecache;
29    NCcachenodecachenode;
30
31    found = 0;
32    if(target == NULL) goto done;
33
34    /* Match the target variable against the prefetch, if any */
35    /* Note that prefetches are always whole variable */
36    cache = nccomm->cdf.cache;
37    cachenode = cache->prefetch;
38    if(cachenode!= NULL) {
39        for(found=0,i=0;i<nclistlength(cachenode->vars);i++) {
40            CDFnodevar = (CDFnode*)nclistget(cachenode->vars,i);
41     if(var == target) {
42                if(cachenodep) *cachenodep = cachenode;
43 found=1;
44 goto done;
45     }
46 }
47    }
48
49    /*search other cache nodes starting at latest first */
50    index = 0;
51    for(i=nclistlength(cache->nodes)-1;i>=0;i--) {
52        cachenode = (NCcachenode*)nclistget(cache->nodes,i);
53 /* We currently do not try to match constraints;
54           If the cachenode is constrained by more than
55           simple wholevariable projections, then skip it.
56        */
57 if(!cachenode->wholevariable) continue;
58        for(found=0,j=0;j<nclistlength(cachenode->vars);j++) {
59            CDFnodevar = (CDFnode*)nclistget(cachenode->vars,j);
60            if(var == target) {found=1;index=i;break;}
61 }
62 if(found) break;
63    }
64
65    if(found) {
66        ASSERT((cachenode != NULL));
67        if(nclistlength(cache->nodes) > 1) {
68     /* Manage the cache nodes as LRU */
69     nclistremove(cache->nodes,index);
70     nclistpush(cache->nodes,(void*)cachenode);
71 }
72        if(cachenodep) *cachenodep = cachenode;
73    }
74
75done:
76#ifdef DEBUG
77fprintf(stderr,"iscached: search: %s\n",makecdfpathstring(target,"."));
78if(found)
79   fprintf(stderr,"iscached: found: %s\n",dumpcachenode(cachenode));
80else
81   fprintf(stderr,"iscached: notfound\n");
82#endif
83    return found;
84}
85
86/* Compute the set of prefetched data.
87   Notes:
88   1. All prefetches are whole variable fetches.
89   2. If the data set is unconstrainable, we
90      will prefetch the whole thing
91*/
92NCerror
93prefetchdata(NCDAPCOMMONnccomm)
94{
95    int i;
96    NCFLAGS flags;
97    NCerror ncstat = NC_NOERR;
98    NClistallvars = nccomm->cdf.ddsroot->tree->varnodes;
99    DCEconstrainturlconstraint = nccomm->oc.dapconstraint;
100    NClistvars = nclistnew();
101    NCcachenodecache = NULL;
102    DCEconstraintnewconstraint = NULL;
103
104    if(FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) {
105        /* If we cannot constrain and caching is enabled,
106           then pull in everything */
107        if(FLAGSET(nccomm->controls,NCF_CACHE)) {
108     for(i=0;i<nclistlength(allvars);i++) {
109         nclistpush(vars,nclistget(allvars,i));
110     }
111 } else { /* do no prefetching */
112         nccomm->cdf.cache->prefetch = NULL;
113     goto done;
114 }
115    } else {
116 /* pull in those variables previously marked as prefetchable */
117        for(i=0;i<nclistlength(allvars);i++) {
118            CDFnodevar = (CDFnode*)nclistget(allvars,i);
119
120     /* Most of the important testing was already done */
121     if(!var->basenode->prefetchable)
122 continue;
123
124     /* Do not attempt to prefetch any variables in the
125               nc_open url's projection list
126     */
127     if(nclistcontains(nccomm->cdf.projectedvars,(void*)var))
128 continue;
129
130     /* Should be prefetchable */
131     nclistpush(vars,(void*)var);
132if(SHOWFETCH) {
133nclog(NCLOGDBG,"prefetch: %s",var->ncfullname);
134}
135 }
136    }
137
138    /* If there are no vars, then do nothing */
139    if(nclistlength(vars) == 0) {
140 nccomm->cdf.cache->prefetch = NULL;
141 goto done;
142    }
143
144    /* Create a single constraint consisting of the projections for the variables;
145       each projection is whole variable. The selections are passed on as is.
146       Conditionally, The exception is if we are prefetching everything.
147    */
148
149    newconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
150    newconstraint->projections = nclistnew();
151    newconstraint->selections = dceclonelist(urlconstraint->selections);
152
153    for(i=0;i<nclistlength(vars);i++) {
154        CDFnodevar = (CDFnode*)nclistget(vars,i);
155 DCEprojectionvarprojection;
156 /* convert var to a projection */
157 ncstat = dapvar2projection(var,&varprojection);
158 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
159 nclistpush(newconstraint->projections,(void*)varprojection);
160    }
161if(SHOWFETCH) {
162char* s = dumpprojections(newconstraint->projections);
163LOG1(NCLOGNOTE,"prefetch.final: %s",s);
164nullfree(s);
165}
166
167    flags = NCF_PREFETCH;
168#ifndef GRADS_PREFETCH
169    if(nclistlength(allvars) == nclistlength(vars)) flags |= NCF_PREFETCH_ALL;
170#endif
171    ncstat = buildcachenode(nccomm,newconstraint,vars,&cache,flags);
172    newconstraint = NULL; /* buildcachenodetakes control of newconstraint */
173    if(ncstat != OC_NOERR) goto done;
174    else if(cache == NULL) goto done;
175    else
176      cache->wholevariable = 1; /* All prefetches are whole variable */
177    /* Make cache node be the prefetch node */
178    nccomm->cdf.cache->prefetch = cache;
179if(SHOWFETCH) {
180LOG0(NCLOGNOTE,"prefetch.complete");
181}
182
183if(SHOWFETCH) {
184char* s = NULL;
185/* Log the set of prefetch variables */
186NCbytesbuf = ncbytesnew();
187ncbytescat(buf,"prefetch.vars: ");
188for(i=0;i<nclistlength(vars);i++) {
189CDFnodevar = (CDFnode*)nclistget(vars,i);
190ncbytescat(buf," ");
191s = makecdfpathstring(var,".");
192ncbytescat(buf,s);
193nullfree(s);
194 }
195ncbytescat(buf,"\n");
196nclog(NCLOGNOTE,"%s",ncbytescontents(buf));
197ncbytesfree(buf);
198 }
199
200done:
201    nclistfree(vars);
202    dcefree((DCEnode*)newconstraint);
203    if(ncstat && cache != NULLfreenccachenode(nccomm,cache);
204    return THROW(ncstat);
205}
206
207NCerror
208buildcachenode(NCDAPCOMMONnccomm,
209         DCEconstraintconstraint,
210 NClistvarlist,
211 NCcachenode** cachep,
212 NCFLAGS flags)
213{
214    NCerror ncstat = NC_NOERR;
215    OCerror ocstat = OC_NOERR;
216    OClink conn = nccomm->oc.conn;
217    OCddsnode ocroot = NULL;
218    CDFnodedxdroot = NULL;
219    NCcachenodecachenode = NULL;
220    char* ce = NULL;
221    int isprefetch = 0;
222
223    if((flags & NCF_PREFETCH) != 0)
224 isprefetch = 1;
225
226#ifndef GRADS_PREFETCH
227    if((flags & NCF_PREFETCH_ALL) == 0)
228#endif
229        ce = dcebuildconstraintstring(constraint);
230
231    ncstat = dap_fetch(nccomm,conn,ce,OCDATADDS,&ocroot);
232    nullfree(ce);
233    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
234
235    ncstat = buildcdftree(nccomm,ocroot,OCDATA,&dxdroot);
236    if(ncstat) {THROWCHK(ncstat); goto done;}
237
238    /* re-struct*/
239    if(!FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE)) {
240        ncstat = restruct(nccomm,dxdroot,nccomm->cdf.fullddsroot,
241    constraint->projections);
242        if(ncstat) {THROWCHK(ncstat); goto done;}
243    }
244
245    /* create the cache node */
246    cachenode = createnccachenode();
247    cachenode->isprefetch = isprefetch;
248    cachenode->vars = nclistclone(varlist);
249    cachenode->datadds = dxdroot;
250    /* Give the constraint over to the cachenode */
251    cachenode->constraint = constraint;
252    constraint = NULL;
253    cachenode->wholevariable = iscacheableconstraint(cachenode->constraint);
254
255    /* save the root content*/
256    cachenode->ocroot = ocroot;
257    ocstat = oc_data_getroot(conn,ocroot,&cachenode->content);
258    if(ocstat) {THROWCHK(ocerrtoncerr(ocstat)); goto done;}
259
260    /* capture the packet size */
261    ocstat = oc_raw_xdrsize(conn,ocroot,&cachenode->xdrsize);
262    if(ocstat) {THROWCHK(ocerrtoncerr(ocstat)); goto done;}
263
264#ifdef DEBUG
265fprintf(stderr,"buildcachenode: new cache node: %s\n",
266 dumpcachenode(cachenode));
267#endif
268    /* Insert into the cache. If not caching, then
269       remove any previous cache node
270    */
271    if(!isprefetch) {
272 NCcachecache = nccomm->cdf.cache;
273 if(cache->nodes == NULLcache->nodes = nclistnew();
274 /* remove cache nodes to get below the max cache size */
275 while(cache->cachesize + cachenode->xdrsize > cache->cachelimit
276       && nclistlength(cache->nodes) > 0) {
277     NCcachenodenode = (NCcachenode*)nclistremove(cache->nodes,0);
278#ifdef DEBUG
279fprintf(stderr,"buildcachenode: purge cache node: %s\n",
280 dumpcachenode(cachenode));
281#endif
282     cache->cachesize -= node->xdrsize;
283     freenccachenode(nccomm,node);
284 }
285 /* Remove cache nodes to get below the max cache count */
286 /* If not caching, then cachecount should be 0 */
287 while(nclistlength(cache->nodes) > cache->cachecount) {
288     NCcachenodenode = (NCcachenode*)nclistremove(cache->nodes,0);
289#ifdef DEBUG
290fprintf(stderr,"buildcachenode: count purge cache node: %s\n",
291 dumpcachenode(node));
292#endif
293     cache->cachesize -= node->xdrsize;
294     freenccachenode(nccomm,node);
295        }
296        nclistpush(nccomm->cdf.cache->nodes,(void*)cachenode);
297        cache->cachesize += cachenode->xdrsize;
298    }
299
300#ifdef DEBUG
301fprintf(stderr,"buildcachenode: %s\n",dumpcachenode(cachenode));
302#endif
303
304done:
305    if(constraint != NULLdcefree((DCEnode*)constraint);
306    if(cachep) *cachep = cachenode;
307    if(ocstat != OC_NOERRncstat = ocerrtoncerr(ocstat);
308    if(ncstat != OC_NOERR) {
309 freecdfroot(dxdroot);
310 freenccachenode(nccomm,cachenode);
311 if(cachep) *cachep = NULL;
312    }
313    return THROW(ncstat);
314}
315
316NCcachenode*
317createnccachenode(void)
318{
319    NCcachenodemem = (NCcachenode*)calloc(1,sizeof(NCcachenode));
320    return mem;
321}
322
323void
324freenccachenode(NCDAPCOMMONnccommNCcachenodenode)
325{
326    if(node == NULL) return;
327#ifdef DEBUG
328fprintf(stderr,"freecachenode: %s\n",
329 dumpcachenode(node));
330#endif
331    oc_data_free(nccomm->oc.conn,node->content);
332    dcefree((DCEnode*)node->constraint);
333    freecdfroot(node->datadds);
334    nclistfree(node->vars);
335    nullfree(node);
336
337}
338
339void
340freenccache(NCDAPCOMMONnccommNCcachecache)
341{
342    int i;
343    if(cache == NULL) return;
344    freenccachenode(nccomm,cache->prefetch);
345    for(i=0;i<nclistlength(cache->nodes);i++) {
346 freenccachenode(nccomm,(NCcachenode*)nclistget(cache->nodes,i));
347    }
348    nclistfree(cache->nodes);
349    nullfree(cache);
350}
351
352NCcache*
353createnccache(void)
354{
355    NCcachec = (NCcache*)calloc(1,sizeof(NCcache));
356    if(c == NULL)
357 return NULL;
358    c->cachelimit = DFALTCACHELIMIT;
359    c->cachesize = 0;
360    c->nodes = nclistnew();
361    c->cachecount = DFALTCACHECOUNT;
362    return c;
363}
364
365static int
366iscacheableprojection(DCEprojectionproj)
367{
368    int i,cacheable;
369    if(proj->discrim != CES_VAR) return 0;
370    cacheable = 1; /* assume so */
371    for(i=0;i<nclistlength(proj->var->segments);i++) {
372        DCEsegmentsegment = (DCEsegment*)nclistget(proj->var->segments,i);
373 if(!dapiswholesegment(segment)) {cacheable = 0; break;}
374    }
375    return cacheable;
376}
377
378static int
379iscacheableconstraint(DCEconstraintcon)
380{
381    int i;
382    if(con == NULL) return 1;
383    if(con->selections != NULL && nclistlength(con->selections) > 0)
384 return 0; /* cant deal with selections */
385    for(i=0;i<nclistlength(con->projections);i++) {
386        if(!iscacheableprojection((DCEprojection*)nclistget(con->projections,i)))
387     return 0;
388    }
389    return 1;
390}
391
392/*
393A variable is prefetchable if
3941. it is atomic
3952. it's size is sufficiently small
3963. it is not contained in sequence or a dimensioned structure.
397*/
398NCerror
399markprefetch(NCDAPCOMMONnccomm)
400{
401    int i,j;
402    NClistallvars = nccomm->cdf.fullddsroot->tree->varnodes;
403    assert(allvars != NULL);
404    /* mark those variables of sufficiently small size */
405    for(i=0;i<nclistlength(allvars);i++) {
406 CDFnodevar = (CDFnode*)nclistget(allvars,i);
407 size_t nelems;
408
409 /* If var is not atomic, then it is not prefetchable */
410 if(var->nctype != NC_Atomic)
411     continue;
412
413        /* if var is under a sequence, then never prefetch */
414        if(dapinsequence(var))
415     continue;
416
417        /* Compute the # of elements in the variable */
418        for(nelems=1,j=0;j<nclistlength(var->array.dimsettrans);j++) {
419            CDFnodedim = (CDFnode*)nclistget(var->array.dimsettrans,j);
420            nelems *= dim->dim.declsize;
421 }
422        if(nelems <= nccomm->cdf.smallsizelimit
423           && FLAGSET(nccomm->controls,NCF_PREFETCH)) {
424          var->prefetchable = 1;
425          if(SHOWFETCH)
426            {
427              extern char* ocfqn(OCddsnode);
428              char *tmp = ocfqn(var->ocnode);
429              nclog(NCLOGDBG,"prefetchable: %s=%lu",
430                    tmp,(unsigned long)nelems);
431              free(tmp);
432            }
433        }
434    }
435    return NC_NOERR;
436}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed