bes  Updated for version 3.20.6
BESUncompressCache.cc
1 
2 // This file is part of bes, A C++ back-end server implementation framework
3 // for the OPeNDAP Data Access Protocol.
4 
5 // Copyright (c) 2015 OPeNDAP, Inc
6 // Author: Nathan Potter <npotter@opendap.org>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #include "BESUncompressCache.h"
23 #include <string>
24 #include <fstream>
25 #include <sstream>
26 #include <sys/stat.h>
27 
28 #include "BESInternalError.h"
29 #include "BESUtil.h"
30 #include "BESDebug.h"
31 #include "TheBESKeys.h"
32 
33 using std::endl;
34 using std::string;
35 
36 BESUncompressCache *BESUncompressCache::d_instance = 0;
37 bool BESUncompressCache::d_enabled = true;
38 
39 const string BESUncompressCache::DIR_KEY = "BES.UncompressCache.dir";
40 const string BESUncompressCache::PREFIX_KEY = "BES.UncompressCache.prefix";
41 const string BESUncompressCache::SIZE_KEY = "BES.UncompressCache.size";
42 
43 unsigned long BESUncompressCache::getCacheSizeFromConfig()
44 {
45  bool found;
46  string size;
47  unsigned long size_in_megabytes = 0;
48  TheBESKeys::TheKeys()->get_value(SIZE_KEY, size, found);
49  if (found) {
50  std::istringstream iss(size);
51  iss >> size_in_megabytes;
52  }
53  else {
54  string msg = "[ERROR] BESUncompressCache::getCacheSize() - The BES Key " + SIZE_KEY
55  + " is not set! It MUST be set to utilize the decompression cache. ";
56  BESDEBUG("cache", msg << endl);
57  throw BESInternalError(msg, __FILE__, __LINE__);
58  }
59  return size_in_megabytes;
60 }
61 
62 string BESUncompressCache::getCacheDirFromConfig()
63 {
64  bool found;
65  string subdir = "";
66  TheBESKeys::TheKeys()->get_value(DIR_KEY, subdir, found);
67 
68  if (!found) {
69  string msg = "[ERROR] BESUncompressCache::getSubDirFromConfig() - The BES Key " + DIR_KEY
70  + " is not set! It MUST be set to utilize the decompression cache. ";
71  BESDEBUG("cache", msg << endl);
72  throw BESInternalError(msg, __FILE__, __LINE__);
73  }
74 
75  return subdir;
76 }
77 
78 string BESUncompressCache::getCachePrefixFromConfig()
79 {
80  bool found;
81  string prefix = "";
82  TheBESKeys::TheKeys()->get_value(PREFIX_KEY, prefix, found);
83  if (found) {
84  prefix = BESUtil::lowercase(prefix);
85  }
86  else {
87  string msg = "[ERROR] BESUncompressCache::getResultPrefix() - The BES Key " + PREFIX_KEY
88  + " is not set! It MUST be set to utilize the decompression cache. ";
89  BESDEBUG("cache", msg << endl);
90  throw BESInternalError(msg, __FILE__, __LINE__);
91  }
92 
93  return prefix;
94 }
95 
123 string BESUncompressCache::get_cache_file_name(const string &src, bool mangle)
124 {
125  string target = src;
126 
127  if (mangle) {
128  string::size_type last_dot = target.rfind('.');
129  if (last_dot != string::npos) {
130  target = target.substr(0, last_dot);
131  }
132  }
134 
135  BESDEBUG("cache", "BESFileLockingCache::get_cache_file_name - target: '" << target << "'" << endl);
136 
137  return target;
138 }
139 
140 BESUncompressCache::BESUncompressCache()
141 {
142  BESDEBUG("cache", "BESUncompressCache::BESUncompressCache() - BEGIN" << endl);
143 
144  d_enabled = true;
145  d_dimCacheDir = getCacheDirFromConfig();
146  d_dimCacheFilePrefix = getCachePrefixFromConfig();
147  d_maxCacheSize = getCacheSizeFromConfig();
148 
149  BESDEBUG("cache",
150  "BESUncompressCache() - Cache configuration params: " << d_dimCacheDir << ", " << d_dimCacheFilePrefix << ", " << d_maxCacheSize << endl);
151 
152  initialize(d_dimCacheDir, d_dimCacheFilePrefix, d_maxCacheSize);
153 
154  BESDEBUG("cache", "BESUncompressCache::BESUncompressCache() - END" << endl);
155 
156 }
157 BESUncompressCache::BESUncompressCache(const string &data_root_dir, const string &cache_dir, const string &prefix,
158  unsigned long long size)
159 {
160  BESDEBUG("cache", "BESUncompressCache::BESUncompressCache() - BEGIN" << endl);
161  d_enabled = true;
162 
163  d_dataRootDir = data_root_dir;
164  d_dimCacheDir = cache_dir;
165  d_dimCacheFilePrefix = prefix;
166  d_maxCacheSize = size;
167 
168  initialize(d_dimCacheDir, d_dimCacheFilePrefix, d_maxCacheSize);
169 
170  BESDEBUG("cache", "BESUncompressCache::BESUncompressCache() - END" << endl);
171 }
172 
174 BESUncompressCache::get_instance(const string &data_root_dir, const string &cache_dir, const string &result_file_prefix,
175  unsigned long long max_cache_size)
176 {
177  if (d_enabled && d_instance == 0) {
178  if (dir_exists(cache_dir)) {
179  d_instance = new BESUncompressCache(data_root_dir, cache_dir, result_file_prefix, max_cache_size);
180  d_enabled = d_instance->cache_enabled();
181  if(!d_enabled){
182  delete d_instance;
183  d_instance = NULL;
184  BESDEBUG("cache", "BESUncompressCache::"<<__func__ << "() - " <<
185  "Cache is DISABLED"<< endl);
186  }
187  else {
188  #ifdef HAVE_ATEXIT
189  atexit(delete_instance);
190  #endif
191  BESDEBUG("cache", "BESUncompressCache::"<<__func__ << "() - " <<
192  "Cache is ENABLED"<< endl);
193  }
194  }
195  }
196  return d_instance;
197 }
198 
204 {
205  if (d_enabled && d_instance == 0) {
206  d_instance = new BESUncompressCache();
207  d_enabled = d_instance->cache_enabled();
208  if(!d_enabled){
209  delete d_instance;
210  d_instance = NULL;
211  BESDEBUG("cache", "BESUncompressCache::"<<__func__ << "() - " <<
212  "Cache is DISABLED"<< endl);
213  }
214  else {
215 #ifdef HAVE_ATEXIT
216  atexit(delete_instance);
217 #endif
218  BESDEBUG("cache", "BESUncompressCache::"<<__func__ << "() - " <<
219  "Cache is ENABLED"<< endl);
220  }
221  }
222 
223  return d_instance;
224 }
225 
226 BESUncompressCache::~BESUncompressCache()
227 {
228  delete_instance();
229 }
230 
243 bool BESUncompressCache::is_valid(const string &cache_file_name, const string &local_id)
244 {
245  // If the cached response is zero bytes in size, it's not valid.
246  // (hmmm...)
247  string datasetFileName = BESUtil::assemblePath(d_dataRootDir, local_id, true);
248 
249  off_t entry_size = 0;
250  time_t entry_time = 0;
251  struct stat buf;
252  if (stat(cache_file_name.c_str(), &buf) == 0) {
253  entry_size = buf.st_size;
254  entry_time = buf.st_mtime;
255  }
256  else {
257  return false;
258  }
259 
260  if (entry_size == 0) return false;
261 
262  time_t dataset_time = entry_time;
263  if (stat(datasetFileName.c_str(), &buf) == 0) {
264  dataset_time = buf.st_mtime;
265  }
266 
267  // Trick: if the d_dataset is not a file, stat() returns error and
268  // the times stay equal and the code uses the cache entry.
269 
270  // TODO Fix this so that the code can get a LMT from the correct handler.
271  // TODO Consider adding a getLastModified() method to the libdap::DDS object to support this
272  // TODO The DDS may be expensive to instantiate - I think the handler may be a better location
273  // for an LMT method, if we can access the handler when/where needed.
274  if (dataset_time > entry_time) return false;
275 
276  return true;
277 }
278 
BESUncompressCache
Definition: BESUncompressCache.h:28
BESFileLockingCache::cache_enabled
bool cache_enabled() const
Definition: BESFileLockingCache.h:198
BESUncompressCache::get_cache_file_name
virtual std::string get_cache_file_name(const std::string &src, bool mangle=true)
Build the name of file that will holds the uncompressed data from 'src' in the cache.
Definition: BESUncompressCache.cc:123
BESUncompressCache::get_instance
static BESUncompressCache * get_instance()
Definition: BESUncompressCache.cc:203
BESFileLockingCache::dir_exists
static bool dir_exists(const std::string &dir)
Definition: BESFileLockingCache.cc:1136
BESUtil::assemblePath
static std::string assemblePath(const std::string &firstPart, const std::string &secondPart, bool leadingSlash=false, bool trailingSlash=false)
Assemble path fragments making sure that they are separated by a single '/' character.
Definition: BESUtil.cc:821
TheBESKeys::TheKeys
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
BESFileLockingCache::initialize
void initialize(const std::string &cache_dir, const std::string &prefix, unsigned long long size)
Initialize an instance of FileLockingCache.
Definition: BESFileLockingCache.cc:116
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
TheBESKeys::get_value
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:272
BESFileLockingCache::get_cache_file_name
virtual std::string get_cache_file_name(const std::string &src, bool mangle=true)
Definition: BESFileLockingCache.cc:451
BESUtil::lowercase
static std::string lowercase(const std::string &s)
Definition: BESUtil.cc:200