37 #include <ConstraintEvaluator.h> 38 #include <DDXParserSAX2.h> 39 #include <XDRStreamMarshaller.h> 40 #include <XDRStreamUnMarshaller.h> 43 #include <mime_util.h> 46 #include "BESDapResponseCache.h" 47 #include "BESDapResponseBuilder.h" 48 #include "BESInternalError.h" 51 #include "TheBESKeys.h" 57 #define BESDEBUG(stream, stuff) 66 const string BESDapResponseCache::PATH_KEY =
"DAP.ResponseCache.path";
67 const string BESDapResponseCache::PREFIX_KEY =
"DAP.ResponseCache.prefix";
68 const string BESDapResponseCache::SIZE_KEY =
"DAP.ResponseCache.size";
70 unsigned long BESDapResponseCache::getCacheSizeFromConfig()
75 unsigned long size_in_megabytes = 0;
78 BESDEBUG(
"dap_response_cache",
79 "BESDapResponseCache::getCacheSizeFromConfig(): Located BES key " << SIZE_KEY<<
"=" << size << endl);
80 istringstream iss(size);
81 iss >> size_in_megabytes;
85 string msg =
"[ERROR] BESDapResponseCache::getCacheSizeFromConfig() - The BES Key " + SIZE_KEY
86 +
" is not set! It MUST be set to utilize the DAP response cache. ";
87 BESDEBUG(
"dap_response_cache", msg);
90 return size_in_megabytes;
93 string BESDapResponseCache::getCachePrefixFromConfig()
99 BESDEBUG(
"dap_response_cache",
100 "BESDapResponseCache::getCachePrefixFromConfig(): Located BES key " << PREFIX_KEY<<
"=" << prefix << endl);
104 string msg =
"[ERROR] BESDapResponseCache::getCachePrefixFromConfig() - The BES Key " + PREFIX_KEY
105 +
" is not set! It MUST be set to utilize the DAP response cache. ";
106 BESDEBUG(
"dap_response_cache", msg);
113 string BESDapResponseCache::getCacheDirFromConfig()
117 string cacheDir =
"";
120 BESDEBUG(
"dap_response_cache",
121 "BESDapResponseCache::getCacheDirFromConfig(): Located BES key " << PATH_KEY<<
"=" << cacheDir << endl);
124 string msg =
"[ERROR] BESDapResponseCache::getCacheDirFromConfig() - The BES Key " + PATH_KEY
125 +
" is not set! It MUST be set to utilize the DAP response cache. ";
126 BESDEBUG(
"dap_response_cache", msg);
132 BESDapResponseCache::BESDapResponseCache()
134 BESDEBUG(
"dap_response_cache",
"BESDapResponseCache::BESDapResponseCache() - BEGIN" << endl);
136 string cacheDir = getCacheDirFromConfig();
137 string prefix = getCachePrefixFromConfig();
138 unsigned long size_in_megabytes = getCacheSizeFromConfig();
140 BESDEBUG(
"dap_response_cache",
141 "BESDapResponseCache::BESDapResponseCache() - Cache config params: " << cacheDir <<
", " << prefix <<
", " << size_in_megabytes << endl);
146 if (!cacheDir.empty() && size_in_megabytes > 0)
147 initialize(cacheDir, prefix, size_in_megabytes);
149 BESDEBUG(
"dap_response_cache",
"BESDapResponseCache::BESDapResponseCache() - END" << endl);
166 if (d_instance == 0) {
167 if (dir_exists(cache_dir)) {
171 atexit(delete_instance);
175 BESDEBUG(
"dap_response_cache",
176 "BESDapResponseCache::get_instance(): Failed to obtain cache! msg: " << bie.
get_message() << endl);
180 BESDEBUG(
"dap_response_cache",
"BESDapResponseCache::get_instance(dir,prefix,size) - d_instance: " << d_instance << endl);
191 if (d_instance == 0) {
192 if (dir_exists(getCacheDirFromConfig())) {
196 atexit(delete_instance);
200 BESDEBUG(
"dap_response_cache",
201 "BESDapResponseCache::get_instance(): Failed to obtain cache! msg: " << bie.
get_message() << endl);
205 BESDEBUG(
"dap_response_cache",
"BESDapResponseCache::get_instance() - d_instance: " << d_instance << endl);
221 bool BESDapResponseCache::is_valid(
const string &cache_file_name,
const string &dataset)
227 off_t entry_size = 0;
228 time_t entry_time = 0;
230 if (stat(cache_file_name.c_str(), &buf) == 0) {
231 entry_size = buf.st_size;
232 entry_time = buf.st_mtime;
238 if (entry_size == 0)
return false;
240 time_t dataset_time = entry_time;
241 if (stat(dataset.c_str(), &buf) == 0) {
242 dataset_time = buf.st_mtime;
250 if (dataset_time > entry_time)
return false;
266 void BESDapResponseCache::read_data_from_cache(
const string &cache_file_name, DDS *fdds)
268 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" Opening cache file: " << cache_file_name << endl);
270 ifstream data(cache_file_name.c_str());
273 string mime = get_next_mime_header(data);
274 while (!mime.empty()) {
275 mime = get_next_mime_header(data);
279 DDXParser ddx_parser(fdds->get_factory());
282 string boundary = read_multipart_boundary(data);
284 read_multipart_headers(data,
"text/xml", dods_ddx);
290 ddx_parser.intern_stream(data, fdds, data_cid, boundary);
293 BESDEBUG(
"dap_response_cache",
"BESDapResponseCache::read_data_from_cache() - [ERROR] DDX Parser Error: " << e.get_error_message() << endl);
298 data_cid = cid_to_header_value(data_cid);
302 read_multipart_headers(data,
"application/octet-stream", dods_data_ddx , data_cid);
307 XDRStreamUnMarshaller um(data);
308 for (DDS::Vars_iter i = fdds->var_begin(); i != fdds->var_end(); i++) {
309 (*i)->deserialize(um, fdds);
318 BESDapResponseCache::get_cached_data_ddx(
const string &cache_file_name, BaseTypeFactory *factory,
319 const string &filename)
321 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" Reading cache for " << cache_file_name << endl);
323 DDS *fdds =
new DDS(factory);
325 fdds->filename(filename);
327 read_data_from_cache(cache_file_name, fdds);
329 fdds->set_factory(0);
333 DDS::Vars_iter i = fdds->var_begin();
334 while (i != fdds->var_end()) {
335 (*i)->set_read_p(
true);
336 (*i++)->set_send_p(
true);
344 ConstraintEvaluator *eval,
string &cache_token)
347 BaseTypeFactory factory;
352 string response_id = dds.filename() +
"#" + constraint;
355 string cache_file_name = get_cache_file_name(response_id,
true);
357 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" cache_file_name: " << cache_file_name << endl);
364 if (!is_valid(cache_file_name, dds.filename()))
365 purge_file(cache_file_name);
367 if (get_read_lock(cache_file_name, fd)) {
368 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" Cache hit (1) for: " << cache_file_name << endl);
369 fdds = get_cached_data_ddx(cache_file_name, &factory, dds.filename());
371 else if (create_and_lock(cache_file_name, fd)) {
374 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" Caching " << cache_file_name <<
", constraint: " << constraint << endl);
377 eval->parse_constraint(constraint, *fdds);
379 if (eval->function_clauses()) {
380 DDS *temp_fdds = eval->eval_function_clauses(*fdds);
385 ofstream data_stream(cache_file_name.c_str());
387 throw BESInternalError(
"Could not open '" + cache_file_name +
"' to write cached response.", __FILE__, __LINE__);
391 string start =
"dataddx_cache_start", boundary =
"dataddx_cache_boundary";
395 ConstraintEvaluator eval;
399 fdds->set_dap_version(
"3.2");
406 set_mime_multipart(data_stream, boundary, start, dods_data_ddx, x_plain,
412 data_stream << CRLF <<
"--" << boundary <<
"--" << CRLF;
416 ConstraintEvaluator eval;
421 fdds->set_dap_version(
"3.2");
430 exclusive_to_shared_lock(fd);
435 unsigned long long size = update_cache_info(cache_file_name);
436 if (cache_too_big(size)) update_and_purge(cache_file_name);
440 else if (get_read_lock(cache_file_name, fd)) {
441 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" cache hit (2) for: " << cache_file_name << endl);
442 fdds = get_cached_data_ddx(cache_file_name, &factory, dds.get_dataset_name());
445 throw BESInternalError(
"Cache error! Unable to acquire DAP Response cache.", __FILE__, __LINE__);
449 BESDEBUG(
"dap_response_cache", __PRETTY_FUNCTION__ <<
" Caught exception, unlocking cache and re-throw." << endl);
455 cache_token = cache_file_name;
exception thrown if inernal error encountered
static string lowercase(const string &s)
virtual std::string get_message()
get the error message for this exception
static BESDapResponseCache * get_instance()
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
virtual void serialize_dap2_data_ddx(std::ostream &out, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, const std::string &boundary, const std::string &start, bool ce_eval=true)
static BESKeys * TheKeys()
virtual std::string get_dataset_name() const
Get the dataset name.