OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
AggMemberDatasetWithDimensionCacheBase.cc
Go to the documentation of this file.
1 // This file is part of the "NcML Module" project, a BES module designed
3 // to allow NcML files to be used to be used as a wrapper to add
4 // AIS to existing datasets of any format.
5 //
6 // Copyright (c) 2010 OPeNDAP, Inc.
7 // Author: Michael Johnson <m.johnson@opendap.org>
8 //
9 // For more information, please also see the main website: http://opendap.org/
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // Please see the files COPYING and COPYRIGHT for more information on the GLPL.
26 //
27 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
30 
31 #include "AggregationException.h" // agg_util
32 #include "Array.h" // libdap
33 #include "BaseType.h" // libdap
34 #include "Constructor.h" // libdap
35 #include "DataDDS.h" // libdap
36 #include "DDS.h" // libdap
37 #include "NCMLDebug.h"
38 #include <sstream>
39 #include <algorithm>
40 
41 using std::string;
42 using libdap::BaseType;
43 using libdap::Constructor;
44 using libdap::DataDDS;
45 using libdap::DDS;
46 
47 static const string DEBUG_CHANNEL("agg_util");
48 
49 namespace agg_util
50 {
51 
52  // Used to init the DimensionCache below with an estimated number of dimensions
53  static const unsigned int DIMENSION_CACHE_INITIAL_SIZE = 4;
54 
56  const std::string& location)
57  : AggMemberDataset(location)
58  , _dimensionCache(DIMENSION_CACHE_INITIAL_SIZE)
59  {
60  }
61 
62  /* virtual */
64  {
65  _dimensionCache.clear();
66  _dimensionCache.resize(0);
67  }
68 
72  , AggMemberDataset(proto)
73  , _dimensionCache(proto._dimensionCache)
74  {
75  }
76 
80  {
81  if (&rhs != this)
82  {
84  _dimensionCache.clear();
85  _dimensionCache = rhs._dimensionCache;
86  }
87  return *this;
88  }
89 
90  /* virtual */
91  unsigned int
93  const std::string& dimName) const
94  {
95  Dimension* pDim =
96  const_cast<AggMemberDatasetWithDimensionCacheBase*>(this)->findDimension(dimName);
97  if (pDim)
98  {
99  return pDim->size;
100  }
101  else
102  {
103  std::ostringstream oss;
104  oss << __PRETTY_FUNCTION__
105  << " Dimension "
106  << dimName
107  << " was not found in the cache!";
108  throw DimensionNotFoundException(oss.str());
109  }
110  }
111 
112  /* virtual */
113  bool
115  const std::string& dimName) const
116  {
117  return bool(
118  const_cast<AggMemberDatasetWithDimensionCacheBase*>(this)->findDimension(dimName)
119  );
120  }
121 
122  /* virtual */
123  void
125  const Dimension& dim,
126  bool throwIfFound)
127  {
128  Dimension* pExistingDim = findDimension(dim.name);
129  if (pExistingDim)
130  {
131  if (!throwIfFound)
132  {
133  *pExistingDim = dim;
134  }
135  else
136  {
137  std::ostringstream msg;
138  msg << __PRETTY_FUNCTION__ <<
139  " Dimension name="
140  << dim.name
141  << " already exists and we were asked to set uniquely!";
142  throw AggregationException(msg.str());
143  }
144  }
145  else
146  {
147  _dimensionCache.push_back(dim);
148  }
149  }
150 
151  /* virtual */
152  void
154  {
155  // Get the dds
156  DataDDS* pDDS = const_cast<DataDDS*>(getDataDDS());
157  VALID_PTR(pDDS);
158 
159  // Recursive add on all of them
160  for (DataDDS::Vars_iter it = pDDS->var_begin();
161  it != pDDS->var_end();
162  ++it)
163  {
164  BaseType* pBT = *it;
165  VALID_PTR(pBT);
166  addDimensionsForVariableRecursive(*pBT);
167  }
168  }
169 
170  /* virtual */
171  void
173  {
174  _dimensionCache.clear();
175  }
176 
177  /* virtual */
178  void
180  {
181  saveDimensionCacheInternal(ostr);
182  }
183 
184  /* virtual */
185  void
187  {
188  loadDimensionCacheInternal(istr);
189  }
190 
191  Dimension*
192  AggMemberDatasetWithDimensionCacheBase::findDimension(
193  const std::string& dimName)
194  {
195  Dimension* ret = 0;
196  for (vector<Dimension>::iterator it = _dimensionCache.begin();
197  it != _dimensionCache.end();
198  ++it)
199  {
200  if (it->name == dimName)
201  {
202  ret = &(*it);
203  }
204  }
205  return ret;
206  }
207 
208  void
209  AggMemberDatasetWithDimensionCacheBase::addDimensionsForVariableRecursive(libdap::BaseType& var)
210  {
211  BESDEBUG_FUNC(DEBUG_CHANNEL, "Adding dimensions for variable name="
212  << var.name()
213  << endl);
214 
215  if (var.type() == libdap::dods_array_c)
216  {
217  BESDEBUG(DEBUG_CHANNEL,
218  " Adding dimensions for array variable name = "
219  << var.name()
220  << endl);
221 
222  libdap::Array& arrVar = dynamic_cast<libdap::Array&>(var);
223  libdap::Array::Dim_iter it;
224  for (it = arrVar.dim_begin(); it != arrVar.dim_end(); ++it)
225  {
226  libdap::Array::dimension& dim = *it;
227  if (!isDimensionCached(dim.name))
228  {
229  Dimension newDim(dim.name, dim.size);
230  setDimensionCacheFor(newDim, false);
231 
232  BESDEBUG(DEBUG_CHANNEL,
233  " Adding dimension: "
234  << newDim.toString()
235  << " to the dataset granule cache..."
236  << endl);
237  }
238  }
239  }
240 
241  else if (var.is_constructor_type()) // then recurse
242  {
243  BESDEBUG(DEBUG_CHANNEL,
244  " Recursing on all variables for constructor variable name = "
245  << var.name()
246  << endl);
247 
248  libdap::Constructor& containerVar = dynamic_cast<libdap::Constructor&>(var);
249  libdap::Constructor::Vars_iter it;
250  for (it = containerVar.var_begin(); it != containerVar.var_end(); ++it)
251  {
252  BESDEBUG(DEBUG_CHANNEL,
253  " Recursing on variable name="
254  << (*it)->name()
255  << endl);
256 
257  addDimensionsForVariableRecursive( *(*it) );
258  }
259  }
260  }
261 
262  // Sort function
263  static bool sIsDimNameLessThan(const Dimension& lhs, const Dimension& rhs)
264  {
265  return (lhs.name < rhs.name);
266  }
267 
268  void
269  AggMemberDatasetWithDimensionCacheBase::saveDimensionCacheInternal(std::ostream& ostr)
270  {
271  BESDEBUG("agg_util", "Saving dimension cache for dataset location = "
272  << getLocation()
273  << " ..." << endl);
274 
275  // Not really necessary, but might help with trying to read output
276  std::sort(_dimensionCache.begin(), _dimensionCache.end(), sIsDimNameLessThan);
277 
278  // Save out the location first, ASSUMES \n is NOT in the location for read back
279  const std::string& loc = getLocation();
280  ostr << loc << '\n';
281 
282  // Now save each dimension
283  unsigned int n = _dimensionCache.size();
284  ostr << n << '\n';
285  for (unsigned int i=0; i<n; ++i)
286  {
287  const Dimension& dim = _dimensionCache.at(i);
288  // note this assumes the dimension names don't contain spaces.
289  ostr << dim.name << '\n' << dim.size << '\n';
290  }
291  }
292 
293  void
294  AggMemberDatasetWithDimensionCacheBase::loadDimensionCacheInternal(std::istream& istr)
295  {
296  BESDEBUG("agg_util", "Loading dimension cache for dataset location = "
297  << getLocation()
298  << " ..." << endl);
299 
300  // Read in the location string
301  std::string loc;
302  getline(istr, loc, '\n');
303 
304  // Make sure the location we read is the same as the location
305  // for this AMD or there's an unrecoverable serialization bug
306  if (loc != getLocation())
307  {
308  stringstream ss;
309  ss << "Serialization error: the location loaded from the "
310  "dimensions cache was: \"" << loc << "\" but we expected it to be "
311  << getLocation() << "\". Unrecoverable!";
312  THROW_NCML_INTERNAL_ERROR(ss.str());
313  }
314 
315  unsigned int n = 0;
316  istr >> n >> ws;
317  for (unsigned int i=0; i<n; ++i)
318  {
319  Dimension newDim;
320  istr >> newDim.name >> ws;
321  istr >> newDim.size >> ws;
322  if (istr.failbit)
323  {
324  // Best we can do is throw an internal error for now.
325  // Perhaps later throw something else that causes a
326  // recreation of the cache
327  THROW_NCML_INTERNAL_ERROR("Parsing dimension cache failed to deserialize from stream.");
328  }
329  }
330  }
331 
332 }
Abstract helper superclass for allowing lazy access to the DataDDS for an aggregation.
virtual bool isDimensionCached(const std::string &dimName) const
Return whether the dimension is already cached, or would have to be loaded to be found.
unsigned int size
Definition: Dimension.h:64
#define BESDEBUG_FUNC(channel, info)
Definition: NCMLDebug.h:58
std::string name
Definition: Dimension.h:61
virtual void setDimensionCacheFor(const Dimension &dim, bool throwIfFound)
Seed the dimension cache using the given dimension, so that later calls to getDimensionSize for dim...
virtual unsigned int getCachedDimensionSize(const std::string &dimName) const
Get the size of the given dimension named dimName cached within the dataset.
Helper class for temporarily hijacking an existing dhi to load a DDX response for one particular file...
virtual void loadDimensionCache(std::istream &istr)
Load the values in the dimension cache from the input stream.
Basic information subclass for cases of dimension not found in an aggregation.
AggMemberDatasetWithDimensionCacheBase & operator=(const AggMemberDatasetWithDimensionCacheBase &rhs)
const std::string & getLocation() const
The location to which the AggMemberDataset refers Note: this could be "" for some subclasses if they ...
virtual const libdap::DataDDS * getDataDDS()=0
Return the DataDDS for the location, loading it in if it hasn't yet been loaded.
Struct for holding information about a dimension of data, minimally a name and a cardinality (size)...
Definition: Dimension.h:50
virtual void flushDimensionCache()
Flush out any cache for the Dimensions so that it will have to be loaded.
AggMemberDataset & operator=(const AggMemberDataset &rhs)
#define THROW_NCML_INTERNAL_ERROR(msg)
Definition: NCMLDebug.h:61
virtual void saveDimensionCache(std::ostream &ostr)
Append the values in the dimension cache to the output stream.
#define VALID_PTR(ptr)
Definition: NCMLDebug.h:88
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
Exception class used by AggregationUtil and other agg_util classes to pass generic exceptions upward ...
virtual void fillDimensionCacheByUsingDataDDS()
Uses the getDataDDS() call in order to find all named dimensions within it and to seed them into the ...
Interface class for a reference counted object.