ncdap3a.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /*********************************************************************
  2. * Copyright 1993, UCAR/Unidata
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. *********************************************************************/
  5. #include "ncdap3.h"
  6. #include "nc3dispatch.h"
  7. #include "ncd3dispatch.h"
  8. #include "dapalign.h"
  9. #include "dapdump.h"
  10. #include "oc.h"
  11. #define getncid(drno) (((NC*)drno)->ext_ncid)
  12. /*Forward*/
  13. static NCerror getseqdimsize(NCDAPCOMMON*, CDFnode* seq, size_t* sizep);
  14. static int fieldindex(CDFnode* parent, CDFnode* child);
  15. static NCerror countsequence(NCDAPCOMMON*, CDFnode* node, size_t*);
  16. static NCerror makeseqdim(NCDAPCOMMON*, CDFnode* node, size_t, CDFnode**);
  17. static NCerror computeseqcountconstraints3(NCDAPCOMMON*,CDFnode*,NCbytes*);
  18. static void computeseqcountconstraints3r(NCDAPCOMMON*, CDFnode*, CDFnode**);
  19. void
  20. freegetvara(Getvara* vara)
  21. {
  22. if(vara == NULL) return;
  23. dcefree((DCEnode*)vara->varaprojection);
  24. nullfree(vara);
  25. }
  26. NCerror
  27. freeNCDAPCOMMON(NCDAPCOMMON* dapcomm)
  28. {
  29. /* abort the metadata file */
  30. (void)nc_abort(getncid(dapcomm));
  31. freenccache(dapcomm,dapcomm->cdf.cache);
  32. nclistfree(dapcomm->cdf.varnodes);
  33. nclistfree(dapcomm->cdf.seqnodes);
  34. nclistfree(dapcomm->cdf.gridnodes);
  35. nclistfree(dapcomm->cdf.usertypes);
  36. nullfree(dapcomm->cdf.recorddimname);
  37. /* free the trees */
  38. freecdfroot34(dapcomm->cdf.ddsroot);
  39. dapcomm->cdf.ddsroot = NULL;
  40. freecdfroot34(dapcomm->cdf.fullddsroot);
  41. dapcomm->cdf.fullddsroot = NULL;
  42. if(dapcomm->oc.ocdasroot != NULL)
  43. oc_root_free(dapcomm->oc.conn,dapcomm->oc.ocdasroot);
  44. dapcomm->oc.ocdasroot = NULL;
  45. oc_close(dapcomm->oc.conn); /* also reclaims remaining OC trees */
  46. nc_urifree(dapcomm->oc.url);
  47. nullfree(dapcomm->oc.urltext);
  48. nullfree(dapcomm->oc.rawurltext);
  49. dcefree((DCEnode*)dapcomm->oc.dapconstraint);
  50. dapcomm->oc.dapconstraint = NULL;
  51. free(dapcomm);
  52. return NC_NOERR;
  53. }
  54. NCerror
  55. addstringdims(NCDAPCOMMON* dapcomm)
  56. {
  57. /* for all variables of string type, we will need another dimension
  58. to represent the string; Accumulate the needed sizes and create
  59. the dimensions with a specific name: either as specified
  60. in DODS{...} attribute set or defaulting to the variable name.
  61. All such dimensions are global.
  62. */
  63. int i;
  64. NClist* varnodes = dapcomm->cdf.varnodes;
  65. CDFnode* globalsdim = NULL;
  66. char dimname[4096];
  67. size_t dimsize;
  68. /* Start by creating the global string dimension */
  69. snprintf(dimname,sizeof(dimname),"maxStrlen%lu",
  70. (unsigned long)dapcomm->cdf.defaultstringlength);
  71. globalsdim = makecdfnode34(dapcomm, dimname, OC_Dimension, OCNULL,
  72. dapcomm->cdf.ddsroot);
  73. nclistpush(dapcomm->cdf.ddsroot->tree->nodes,(ncelem)globalsdim);
  74. DIMFLAGSET(globalsdim,CDFDIMSTRING);
  75. globalsdim->dim.declsize = dapcomm->cdf.defaultstringlength;
  76. globalsdim->dim.declsize0 = globalsdim->dim.declsize;
  77. globalsdim->dim.array = dapcomm->cdf.ddsroot;
  78. globalsdim->ncbasename = cdflegalname3(dimname);
  79. globalsdim->ncfullname = nulldup(globalsdim->ncbasename);
  80. dapcomm->cdf.globalstringdim = globalsdim;
  81. for(i=0;i<nclistlength(varnodes);i++) {
  82. CDFnode* var = (CDFnode*)nclistget(varnodes,i);
  83. CDFnode* sdim = NULL;
  84. /* Does this node need a string dim? */
  85. if(var->etype != NC_STRING && var->etype != NC_URL) continue;
  86. dimsize = 0;
  87. if(var->dodsspecial.maxstrlen > 0)
  88. dimsize = var->dodsspecial.maxstrlen;
  89. else
  90. dimsize = var->maxstringlength;
  91. /* check is a variable-specific string length was specified */
  92. if(dimsize == 0)
  93. sdim = dapcomm->cdf.globalstringdim; /* use default */
  94. else {
  95. /* create a psuedo dimension for the charification of the string*/
  96. if(var->dodsspecial.dimname != NULL)
  97. strncpy(dimname,var->dodsspecial.dimname,sizeof(dimname));
  98. else
  99. snprintf(dimname,sizeof(dimname),"maxStrlen%lu",
  100. (unsigned long)dimsize);
  101. sdim = makecdfnode34(dapcomm, dimname, OC_Dimension, OCNULL,
  102. dapcomm->cdf.ddsroot);
  103. if(sdim == NULL) return THROW(NC_ENOMEM);
  104. nclistpush(dapcomm->cdf.ddsroot->tree->nodes,(ncelem)sdim);
  105. DIMFLAGSET(sdim,CDFDIMSTRING);
  106. sdim->dim.declsize = dimsize;
  107. sdim->dim.declsize0 = dimsize;
  108. sdim->dim.array = var;
  109. sdim->ncbasename = cdflegalname3(sdim->ocname);
  110. sdim->ncfullname = nulldup(sdim->ncbasename);
  111. }
  112. /* tag the variable with its string dimension*/
  113. var->array.stringdim = sdim;
  114. }
  115. return NC_NOERR;
  116. }
  117. NCerror
  118. defrecorddim3(NCDAPCOMMON* dapcomm)
  119. {
  120. unsigned int i;
  121. NCerror ncstat = NC_NOERR;
  122. NClist* basedims;
  123. if(dapcomm->cdf.recorddimname == NULL) return NC_NOERR; /* ignore */
  124. /* Locate the base dimension matching the record dim */
  125. basedims = dapcomm->cdf.dimnodes;
  126. for(i=0;i<nclistlength(basedims);i++) {
  127. CDFnode* dim = (CDFnode*)nclistget(basedims,i);
  128. if(strcmp(dim->ocname,dapcomm->cdf.recorddimname) != 0) continue;
  129. DIMFLAGSET(dim,CDFDIMRECORD);
  130. dapcomm->cdf.recorddim = dim;
  131. break;
  132. }
  133. return ncstat;
  134. }
  135. NCerror
  136. defseqdims(NCDAPCOMMON* dapcomm)
  137. {
  138. unsigned int i;
  139. NCerror ncstat = NC_NOERR;
  140. int seqdims = 1; /* default is to compute seq dims counts */
  141. /* Does the user want to compute actual sequence sizes? */
  142. if(paramvalue34(dapcomm,"noseqdims")) seqdims = 0;
  143. /*
  144. Compute and define pseudo dimensions for sequences
  145. meeting the following qualifications:
  146. 1. all parents (transitively) of the sequence must
  147. be either a dataset or a scalar structure.
  148. 2. it must be possible to find a usable sequence constraint.
  149. All other sequences will be ignored.
  150. */
  151. for(i=0;i<nclistlength(dapcomm->cdf.seqnodes);i++) {
  152. CDFnode* seq = (CDFnode*)nclistget(dapcomm->cdf.seqnodes,i);
  153. size_t seqsize;
  154. CDFnode* sqdim = NULL;
  155. CDFnode* container;
  156. /* Does this sequence match the requirements for use ? */
  157. seq->usesequence = 1; /* assume */
  158. for(container=seq->container;container != NULL;container=container->container) {
  159. if(container->nctype == NC_Dataset) break;
  160. if(container->nctype != NC_Structure
  161. || nclistlength(container->array.dimset0) > 0)
  162. {seq->usesequence = 0; break;}/* no good */
  163. }
  164. /* Does the user want us to compute the actual sequence dim size? */
  165. if(seq->usesequence && seqdims) {
  166. ncstat = getseqdimsize(dapcomm,seq,&seqsize);
  167. if(ncstat != NC_NOERR) {
  168. /* Cannot read sequence; mark as unusable */
  169. seq->usesequence = 0;
  170. }
  171. } else { /* !seqdims default to size = 1 */
  172. seqsize = 1;
  173. }
  174. if(seq->usesequence) {
  175. /* Note: we are making the dimension in the dds root tree */
  176. ncstat = makeseqdim(dapcomm,seq,seqsize,&sqdim);
  177. if(ncstat) goto fail;
  178. seq->array.seqdim = sqdim;
  179. } else
  180. seq->array.seqdim = NULL;
  181. }
  182. fail:
  183. return ncstat;
  184. }
  185. static NCerror
  186. getseqdimsize(NCDAPCOMMON* dapcomm, CDFnode* seq, size_t* sizep)
  187. {
  188. NCerror ncstat = NC_NOERR;
  189. OCerror ocstat = OC_NOERR;
  190. OCconnection conn = dapcomm->oc.conn;
  191. OCdata rootcontent = OCNULL;
  192. OCobject ocroot;
  193. CDFnode* dxdroot;
  194. CDFnode* xseq;
  195. NCbytes* seqcountconstraints = ncbytesnew();
  196. size_t seqsize;
  197. /* Read the minimal amount of data in order to get the count */
  198. /* If the url is unconstrainable, then get the whole thing */
  199. computeseqcountconstraints3(dapcomm,seq,seqcountconstraints);
  200. #ifdef DEBUG
  201. fprintf(stderr,"seqcountconstraints: %s\n",ncbytescontents(seqcountconstraints));
  202. #endif
  203. /* Fetch the minimal data */
  204. if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
  205. ocstat = dap_fetch(dapcomm,conn,NULL,OCDATADDS,&ocroot);
  206. else
  207. ocstat = dap_fetch(dapcomm,conn,ncbytescontents(seqcountconstraints),OCDATADDS,&ocroot);
  208. if(ocstat) goto fail;
  209. ncstat = buildcdftree34(dapcomm,ocroot,OCDATA,&dxdroot);
  210. if(ncstat) goto fail;
  211. /* attach DATADDS to DDS */
  212. ncstat = attach34(dxdroot,seq);
  213. if(ncstat) goto fail;
  214. /* WARNING: we are now switching to datadds tree */
  215. xseq = seq->attachment;
  216. ncstat = countsequence(dapcomm,xseq,&seqsize);
  217. if(ncstat) goto fail;
  218. #ifdef DEBUG
  219. fprintf(stderr,"sequencesize: %s = %lu\n",seq->ocname,(unsigned long)seqsize);
  220. #endif
  221. /* throw away the fetch'd trees */
  222. unattach34(dapcomm->cdf.ddsroot);
  223. freecdfroot34(dxdroot);
  224. if(ncstat != NC_NOERR) {
  225. /* Cannot get DATADDDS*/
  226. char* code;
  227. char* msg;
  228. long httperr;
  229. oc_svcerrordata(dapcomm->oc.conn,&code,&msg,&httperr);
  230. if(code != NULL) {
  231. nclog(NCLOGERR,"oc_fetch_datadds failed: %s %s %l",
  232. code,msg,httperr);
  233. }
  234. ocstat = OC_NOERR;
  235. }
  236. if(sizep) *sizep = seqsize;
  237. fail:
  238. ncbytesfree(seqcountconstraints);
  239. oc_data_free(conn,rootcontent);
  240. if(ocstat) ncstat = ocerrtoncerr(ocstat);
  241. return ncstat;
  242. }
  243. static NCerror
  244. makeseqdim(NCDAPCOMMON* dapcomm, CDFnode* seq, size_t count, CDFnode** sqdimp)
  245. {
  246. CDFnode* sqdim;
  247. CDFnode* root = seq->root;
  248. CDFtree* tree = root->tree;
  249. /* build the dimension with given size; keep the dimension anonymous */
  250. sqdim = makecdfnode34(dapcomm,seq->ocname,OC_Dimension,OCNULL,root);
  251. if(sqdim == NULL) return THROW(NC_ENOMEM);
  252. nclistpush(tree->nodes,(ncelem)sqdim);
  253. /* Assign a name to the sequence node */
  254. sqdim->ncbasename = cdflegalname3(seq->ocname);
  255. sqdim->ncfullname = nulldup(sqdim->ncbasename);
  256. DIMFLAGSET(sqdim,CDFDIMSEQ);
  257. sqdim->dim.declsize = count;
  258. sqdim->dim.declsize0 = count;
  259. sqdim->dim.array = seq;
  260. if(sqdimp) *sqdimp = sqdim;
  261. return NC_NOERR;
  262. }
  263. static NCerror
  264. countsequence(NCDAPCOMMON* dapcomm, CDFnode* xseq, size_t* sizep)
  265. {
  266. unsigned int i;
  267. NClist* path = nclistnew();
  268. int index;
  269. OCerror ocstat = OC_NOERR;
  270. NCerror ncstat = NC_NOERR;
  271. OCconnection conn = dapcomm->oc.conn;
  272. size_t recordcount;
  273. CDFnode* xroot;
  274. CDFnode* current;
  275. OCdata datacontainer = OCNULL;
  276. OCmode mode;
  277. ASSERT((xseq->nctype == NC_Sequence));
  278. /* collect the path to the sequence node */
  279. collectnodepath3(xseq,path,WITHDATASET);
  280. /* Get tree root */
  281. xroot = xseq->root;
  282. datacontainer = oc_data_new(conn);
  283. ocstat = oc_data_root(conn,xroot->tree->ocroot,datacontainer);
  284. if(ocstat) goto fail;
  285. /* walk to the sequence object; control the movement to the next node
  286. based on mode */
  287. current = (CDFnode*)nclistget(path,0);
  288. for(i=0;;) {
  289. OCdata child = OCNULL;
  290. CDFnode* next = NULL;
  291. ocstat = oc_data_mode(conn,datacontainer,&mode);
  292. if(ocstat != OC_NOERR) goto fail;
  293. switch (mode) {
  294. case OCFIELDMODE:
  295. i++;
  296. next = (CDFnode*)nclistget(path,i);
  297. index = fieldindex(current,next);
  298. break;
  299. case OCARRAYMODE:
  300. index = 0;
  301. break;
  302. case OCSEQUENCEMODE:
  303. goto exitloop;
  304. default:
  305. PANIC("unexpected mode");
  306. return NC_EINVAL;
  307. }
  308. child = oc_data_new(conn);
  309. ocstat = oc_data_ith(conn,datacontainer,index,child);
  310. if(ocstat) goto fail;
  311. /* move to the next node only if it is defined */
  312. if(next != NULL)
  313. current = next;
  314. oc_data_free(conn,datacontainer);
  315. datacontainer = child;
  316. }
  317. exitloop:
  318. ASSERT(current == xseq && mode == OCSEQUENCEMODE);
  319. oc_data_count(conn,datacontainer,&recordcount);
  320. if(sizep) *sizep = recordcount;
  321. fail:
  322. oc_data_free(conn,datacontainer);
  323. nclistfree(path);
  324. if(ocstat) ncstat = ocerrtoncerr(ocstat);
  325. return THROW(ncstat);
  326. }
  327. static int
  328. fieldindex(CDFnode* parent, CDFnode* child)
  329. {
  330. unsigned int i;
  331. for(i=0;i<nclistlength(parent->subnodes);i++) {
  332. CDFnode* node = (CDFnode*)nclistget(parent->subnodes,i);
  333. if(node == child) return i;
  334. }
  335. return -1;
  336. }
  337. NCerror
  338. showprojection3(NCDAPCOMMON* dapcomm, CDFnode* var)
  339. {
  340. int i,rank;
  341. NCerror ncstat = NC_NOERR;
  342. NCbytes* projection = ncbytesnew();
  343. NClist* path = nclistnew();
  344. NC* drno = dapcomm->controller;
  345. /* Collect the set of DDS node name forming the xpath */
  346. collectnodepath3(var,path,WITHOUTDATASET);
  347. for(i=0;i<nclistlength(path);i++) {
  348. CDFnode* node = (CDFnode*)nclistget(path,i);
  349. if(i > 0) ncbytescat(projection,".");
  350. ncbytescat(projection,node->ocname);
  351. }
  352. /* Now, add the dimension info */
  353. rank = nclistlength(var->array.dimset0);
  354. for(i=0;i<rank;i++) {
  355. CDFnode* dim = (CDFnode*)nclistget(var->array.dimset0,i);
  356. char tmp[32];
  357. ncbytescat(projection,"[");
  358. snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)dim->dim.declsize);
  359. ncbytescat(projection,tmp);
  360. ncbytescat(projection,"]");
  361. }
  362. /* Define the attribute */
  363. ncstat = nc_put_att_text(getncid(drno),var->ncid,
  364. "_projection",
  365. ncbyteslength(projection),
  366. ncbytescontents(projection));
  367. return ncstat;
  368. }
  369. /*
  370. This is more complex than one might think. We want to find
  371. a path to a variable inside the given node so that we can
  372. ask for a single instance of that variable to minimize the
  373. amount of data we retrieve. However, we want to avoid passing
  374. through any nested sequence. This is possible because of the way
  375. that sequencecheck() works.
  376. TODO: some servers will not accept an unconstrained fetch, so
  377. make sure we always have a constraint.
  378. */
  379. static NCerror
  380. computeseqcountconstraints3(NCDAPCOMMON* dapcomm, CDFnode* seq, NCbytes* seqcountconstraints)
  381. {
  382. int i,j;
  383. NClist* path = NULL;
  384. CDFnode* var = NULL;
  385. ASSERT(seq->nctype == NC_Sequence);
  386. computeseqcountconstraints3r(dapcomm,seq,&var);
  387. ASSERT((var != NULL));
  388. /* Compute var path */
  389. path = nclistnew();
  390. collectnodepath3(var,path,WITHOUTDATASET);
  391. /* construct the projection path using minimal index values */
  392. for(i=0;i<nclistlength(path);i++) {
  393. CDFnode* node = (CDFnode*)nclistget(path,i);
  394. if(i > 0) ncbytescat(seqcountconstraints,".");
  395. ncbytescat(seqcountconstraints,node->ocname);
  396. if(node == seq) {
  397. /* Use the limit */
  398. if(node->sequencelimit > 0) {
  399. char tmp[64];
  400. snprintf(tmp,sizeof(tmp),"[0:%lu]",
  401. (unsigned long)(node->sequencelimit - 1));
  402. ncbytescat(seqcountconstraints,tmp);
  403. }
  404. } else if(nclistlength(node->array.dimset0) > 0) {
  405. int ndims = nclistlength(node->array.dimset0);
  406. for(j=0;j<ndims;j++) {
  407. CDFnode* dim = (CDFnode*)nclistget(node->array.dimset0,j);
  408. if(DIMFLAG(dim,CDFDIMSTRING)) {
  409. ASSERT((j == (ndims - 1)));
  410. break;
  411. }
  412. ncbytescat(seqcountconstraints,"[0]");
  413. }
  414. }
  415. }
  416. /* Finally, add in any selection from the original URL */
  417. if(dapcomm->oc.url->selection != NULL)
  418. ncbytescat(seqcountconstraints,dapcomm->oc.url->selection);
  419. nclistfree(path);
  420. return NC_NOERR;
  421. }
  422. /* Given an existing candidate, see if we prefer newchoice */
  423. static CDFnode*
  424. prefer(CDFnode* candidate, CDFnode* newchoice)
  425. {
  426. nc_type newtyp;
  427. nc_type cantyp;
  428. int newisstring;
  429. int canisstring;
  430. int newisscalar;
  431. int canisscalar;
  432. /* always choose !null over null */
  433. if(newchoice == NULL)
  434. return candidate;
  435. if(candidate == NULL)
  436. return newchoice;
  437. newtyp = newchoice->etype;
  438. cantyp = candidate->etype;
  439. newisstring = (newtyp == NC_STRING || newtyp == NC_URL);
  440. canisstring = (cantyp == NC_STRING || cantyp == NC_URL);
  441. newisscalar = (nclistlength(newchoice->array.dimset0) == 0);
  442. canisscalar = (nclistlength(candidate->array.dimset0) == 0);
  443. ASSERT(candidate->nctype == NC_Primitive && newchoice->nctype == NC_Primitive);
  444. /* choose non-string over string */
  445. if(canisstring && !newisstring)
  446. return newchoice;
  447. if(!canisstring && newisstring)
  448. return candidate;
  449. /* choose scalar over array */
  450. if(canisscalar && !newisscalar)
  451. return candidate;
  452. if(!canisscalar && newisscalar)
  453. return candidate;
  454. /* otherwise choose existing candidate */
  455. return candidate;
  456. }
  457. /* computeseqcountconstraints3 recursive helper function */
  458. static void
  459. computeseqcountconstraints3r(NCDAPCOMMON* dapcomm, CDFnode* node, CDFnode** candidatep)
  460. {
  461. CDFnode* candidate;
  462. CDFnode* compound;
  463. unsigned int i;
  464. candidate = NULL;
  465. compound = NULL;
  466. for(i=0;i<nclistlength(node->subnodes);i++){
  467. CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,i);
  468. if(subnode->nctype == NC_Structure || subnode->nctype == NC_Grid)
  469. compound = subnode; /* save for later recursion */
  470. else if(subnode->nctype == NC_Primitive) {
  471. candidate = prefer(candidate,subnode);
  472. }
  473. }
  474. if(candidate == NULL && compound == NULL) {
  475. PANIC("cannot find candidate for seqcountconstraints for a sequence");
  476. } else if(candidate != NULL && candidatep != NULL) {
  477. *candidatep = candidate;
  478. } else { /* compound != NULL by construction */
  479. /* recurse on a nested grids or strucures */
  480. computeseqcountconstraints3r(dapcomm,compound,candidatep);
  481. }
  482. }
  483. static unsigned long
  484. cdftotalsize3(NClist* dimensions)
  485. {
  486. unsigned int i;
  487. unsigned long total = 1;
  488. if(dimensions != NULL) {
  489. for(i=0;i<nclistlength(dimensions);i++) {
  490. CDFnode* dim = (CDFnode*)nclistget(dimensions,i);
  491. total *= dim->dim.declsize;
  492. }
  493. }
  494. return total;
  495. }
  496. /* Estimate variables sizes and then resort the variable list
  497. by that size
  498. */
  499. void
  500. estimatevarsizes3(NCDAPCOMMON* dapcomm)
  501. {
  502. int ivar;
  503. unsigned int rank;
  504. size_t totalsize = 0;
  505. for(ivar=0;ivar<nclistlength(dapcomm->cdf.varnodes);ivar++) {
  506. CDFnode* var = (CDFnode*)nclistget(dapcomm->cdf.varnodes,ivar);
  507. NClist* ncdims = var->array.dimset0;
  508. rank = nclistlength(ncdims);
  509. if(rank == 0) { /* use instance size of the type */
  510. var->estimatedsize = nctypesizeof(var->etype);
  511. #ifdef DEBUG1
  512. fprintf(stderr,"scalar %s.estimatedsize = %lu\n",
  513. makecdfpathstring3(var,"."),var->estimatedsize);
  514. #endif
  515. } else {
  516. unsigned long size = cdftotalsize3(ncdims);
  517. size *= nctypesizeof(var->etype);
  518. #ifdef DEBUG1
  519. fprintf(stderr,"array %s(%u).estimatedsize = %lu\n",
  520. makecdfpathstring3(var,"."),rank,size);
  521. #endif
  522. var->estimatedsize = size;
  523. }
  524. totalsize += var->estimatedsize;
  525. }
  526. #ifdef DEBUG1
  527. fprintf(stderr,"total estimatedsize = %lu\n",totalsize);
  528. #endif
  529. dapcomm->cdf.totalestimatedsize = totalsize;
  530. }
  531. NCerror
  532. fetchtemplatemetadata3(NCDAPCOMMON* dapcomm)
  533. {
  534. NCerror ncstat = NC_NOERR;
  535. OCerror ocstat = OC_NOERR;
  536. OCobject ocroot = OCNULL;
  537. CDFnode* ddsroot = NULL;
  538. char* ce = NULL;
  539. /* Temporary hack: we need to get the selection string
  540. from the url
  541. */
  542. /* Get (almost) unconstrained DDS; In order to handle functions
  543. correctly, those selections must always be included
  544. */
  545. if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
  546. ce = NULL;
  547. else
  548. ce = nulldup(dapcomm->oc.url->selection);
  549. /* Get selection constrained DDS */
  550. ocstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDDS,&ocroot);
  551. if(ocstat != OC_NOERR) {
  552. /* Special Hack. If the protocol is file, then see if
  553. we can get the dds from the .dods file
  554. */
  555. if(strcmp(dapcomm->oc.url->protocol,"file") != 0) {
  556. THROWCHK(ocstat); goto done;
  557. }
  558. /* Fetch the data dds */
  559. ocstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDATADDS,&ocroot);
  560. if(ocstat != OC_NOERR) {
  561. THROWCHK(ocstat); goto done;
  562. }
  563. /* Note what we did */
  564. nclog(NCLOGWARN,"Cannot locate .dds file, using .dods file");
  565. }
  566. /* Get selection constrained DAS */
  567. ocstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDAS,&dapcomm->oc.ocdasroot);
  568. if(ocstat != OC_NOERR) {
  569. /* Ignore but complain */
  570. nclog(NCLOGWARN,"Could not read DAS; ignored");
  571. dapcomm->oc.ocdasroot = OCNULL;
  572. ocstat = OC_NOERR;
  573. }
  574. /* Construct our parallel dds tree */
  575. ncstat = buildcdftree34(dapcomm,ocroot,OCDDS,&ddsroot);
  576. if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
  577. dapcomm->cdf.fullddsroot = ddsroot;
  578. done:
  579. nullfree(ce);
  580. if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
  581. return ncstat;
  582. }
  583. NCerror
  584. fetchconstrainedmetadata3(NCDAPCOMMON* dapcomm)
  585. {
  586. NCerror ncstat = NC_NOERR;
  587. OCerror ocstat = OC_NOERR;
  588. OCobject ocroot;
  589. CDFnode* ddsroot; /* constrained */
  590. char* ce = NULL;
  591. if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
  592. ce = NULL;
  593. else
  594. ce = buildconstraintstring3(dapcomm->oc.dapconstraint);
  595. {
  596. ocstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDDS,&ocroot);
  597. if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
  598. /* Construct our parallel dds tree; including attributes*/
  599. ncstat = buildcdftree34(dapcomm,ocroot,OCDDS,&ddsroot);
  600. if(ncstat) goto fail;
  601. dapcomm->cdf.ddsroot = ddsroot;
  602. if(!FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
  603. /* fix DAP server problem by adding back any missing grid structure nodes */
  604. ncstat = regrid3(ddsroot,dapcomm->cdf.fullddsroot,dapcomm->oc.dapconstraint->projections);
  605. if(ncstat) goto fail;
  606. }
  607. #ifdef DEBUG
  608. fprintf(stderr,"constrained:\n%s",dumptree(ddsroot));
  609. #endif
  610. /* Combine DDS and DAS */
  611. if(dapcomm->oc.ocdasroot != NULL) {
  612. ncstat = dapmerge3(dapcomm,ddsroot,dapcomm->oc.ocdasroot);
  613. if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
  614. }
  615. /* map the constrained DDS to the unconstrained DDS */
  616. ncstat = mapnodes3(ddsroot,dapcomm->cdf.fullddsroot);
  617. if(ncstat) goto fail;
  618. }
  619. fail:
  620. nullfree(ce);
  621. if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
  622. return ncstat;
  623. }
  624. /* Suppress variables not in usable sequences*/
  625. NCerror
  626. suppressunusablevars3(NCDAPCOMMON* dapcomm)
  627. {
  628. int i,j;
  629. int found = 1;
  630. NClist* path = nclistnew();
  631. while(found) {
  632. found = 0;
  633. /* Walk backwards to aid removal semantics */
  634. for(i=nclistlength(dapcomm->cdf.varnodes)-1;i>=0;i--) {
  635. CDFnode* var = (CDFnode*)nclistget(dapcomm->cdf.varnodes,i);
  636. /* See if this var is under an unusable sequence */
  637. nclistclear(path);
  638. collectnodepath3(var,path,WITHOUTDATASET);
  639. for(j=0;j<nclistlength(path);j++) {
  640. CDFnode* node = (CDFnode*)nclistget(path,j);
  641. if(node->nctype == NC_Sequence
  642. && !node->usesequence) {
  643. #ifdef DEBUG
  644. fprintf(stderr,"suppressing var in unusable sequence: %s.%s\n",node->ncfullname,var->ncbasename);
  645. #endif
  646. found = 1;
  647. break;
  648. }
  649. }
  650. if(found) break;
  651. }
  652. if(found) nclistremove(dapcomm->cdf.varnodes,i);
  653. }
  654. nclistfree(path);
  655. return NC_NOERR;
  656. }
  657. /*
  658. For variables which have a zero size dimension,
  659. make them invisible.
  660. */
  661. NCerror
  662. fixzerodims3(NCDAPCOMMON* dapcomm)
  663. {
  664. int i,j;
  665. for(i=0;i<nclistlength(dapcomm->cdf.varnodes);i++) {
  666. CDFnode* var = (CDFnode*)nclistget(dapcomm->cdf.varnodes,i);
  667. NClist* ncdims = var->array.dimsetplus;
  668. if(nclistlength(ncdims) == 0) continue;
  669. for(j=0;j<nclistlength(ncdims);j++) {
  670. CDFnode* dim = (CDFnode*)nclistget(ncdims,j);
  671. if(dim->dim.declsize == 0) {
  672. /* make node invisible */
  673. var->visible = 0;
  674. var->zerodim = 1;
  675. }
  676. }
  677. }
  678. return NC_NOERR;
  679. }
  680. void
  681. applyclientparamcontrols3(NCDAPCOMMON* dapcomm)
  682. {
  683. /* clear the flags */
  684. CLRFLAG(dapcomm->controls,NCF_CACHE);
  685. CLRFLAG(dapcomm->controls,NCF_PREFETCH);
  686. CLRFLAG(dapcomm->controls,NCF_SHOWFETCH);
  687. CLRFLAG(dapcomm->controls,NCF_NC3);
  688. CLRFLAG(dapcomm->controls,NCF_NCDAP);
  689. /* Turn on any default on flags */
  690. SETFLAG(dapcomm->controls,DFALT_ON_FLAGS);
  691. SETFLAG(dapcomm->controls,(NCF_NC3|NCF_NCDAP));
  692. /* enable/disable caching */
  693. if(paramcheck34(dapcomm,"cache",NULL))
  694. SETFLAG(dapcomm->controls,NCF_CACHE);
  695. else if(paramcheck34(dapcomm,"nocache",NULL))
  696. CLRFLAG(dapcomm->controls,NCF_CACHE);
  697. /* enable/disable cache prefetch */
  698. if(paramcheck34(dapcomm,"prefetch",NULL))
  699. SETFLAG(dapcomm->controls,NCF_PREFETCH);
  700. else if(paramcheck34(dapcomm,"noprefetch",NULL))
  701. CLRFLAG(dapcomm->controls,NCF_PREFETCH);
  702. if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
  703. SETFLAG(dapcomm->controls,NCF_CACHE);
  704. if(paramcheck34(dapcomm,"show","fetch"))
  705. SETFLAG(dapcomm->controls,NCF_SHOWFETCH);
  706. nclog(NCLOGNOTE,"Caching=%d",FLAGSET(dapcomm->controls,NCF_CACHE));
  707. }