bes  Updated for version 3.20.10
BESH4MCache.cc
1 // This file includes cache handling routines for the HDF4 handler.
3 // The skeleton of the code is adapted from BESDapResponseCache.cc under bes/dap
4 // Authors: MuQun Yang <myang6@hdfgroup.org>
5 // Copyright (c) 2014 The HDF Group
7 
8 #include "config.h"
9 
10 #include <sys/stat.h>
11 #include <iostream>
12 #include <sstream>
13 
14 #include "BESH4MCache.h"
15 #include "BESUtil.h"
16 
17 #include "BESInternalError.h"
18 #include "TheBESKeys.h"
19 #include "BESDebug.h"
20 #include "HDF4RequestHandler.h"
21 
22 using namespace std;
23 
24 BESH4Cache *BESH4Cache::d_instance = 0;
25 bool BESH4Cache::d_enabled = true;
26 
27 const string BESH4Cache::PATH_KEY = "HDF4.Cache.latlon.path";
28 const string BESH4Cache::PREFIX_KEY = "HDF4.Cache.latlon.prefix";
29 const string BESH4Cache::SIZE_KEY = "HDF4.Cache.latlon.size";
30 
31 long BESH4Cache::getCacheSizeFromConfig()
32 {
33  if (HDF4RequestHandler::get_cache_latlon_size_exist() == true) {
34  BESDEBUG("cache",
35  "In BESH4Cache::getCacheSize(): Located BES key " << SIZE_KEY<< "=" << HDF4RequestHandler::get_cache_latlon_size() << endl);
36  return HDF4RequestHandler::get_cache_latlon_size();
37  }
38  else {
39  string msg = "[ERROR] BESH4Cache::getCacheSize() - The BES Key " + SIZE_KEY
40  + " is not set! It MUST be set to utilize the HDF4 cache. ";
41  BESDEBUG("cache", msg);
42  throw BESInternalError(msg, __FILE__, __LINE__);
43  }
44 }
45 
46 string BESH4Cache::getCachePrefixFromConfig()
47 {
48  if (HDF4RequestHandler::get_cache_latlon_prefix_exist() == true) {
49  BESDEBUG("cache",
50  "In BESH4Cache::getCachePrefix(): Located BES key " << PREFIX_KEY<< "=" << HDF4RequestHandler::get_cache_latlon_prefix() << endl);
51  return HDF4RequestHandler::get_cache_latlon_prefix();
52  }
53  else {
54  string msg = "[ERROR] BESH4Cache::getCachePrefix() - The BES Key " + PREFIX_KEY
55  + " is not set! It MUST be set to utilize the HDF4 cache. ";
56  BESDEBUG("cache", msg);
57  throw BESInternalError(msg, __FILE__, __LINE__);
58  }
59 }
60 
61 string BESH4Cache::getCacheDirFromConfig()
62 {
63  if (HDF4RequestHandler::get_cache_latlon_path_exist() == true) {
64  BESDEBUG("cache",
65  "In BESH4Cache::getCacheDirFromConfig(): Located BES key " << PATH_KEY<< "=" << HDF4RequestHandler::get_cache_latlon_path() << endl);
66  return HDF4RequestHandler::get_cache_latlon_path();
67  }
68  else {
69  string msg = "[ERROR] BESH4Cache::getCachePrefix() - The BES Key " + PREFIX_KEY
70  + " is not set! It MUST be set to utilize the HDF4 cache. ";
71  BESDEBUG("cache", msg);
72  throw BESInternalError(msg, __FILE__, __LINE__);
73  }
74 }
75 
76 BESH4Cache::BESH4Cache()
77 {
78  BESDEBUG("cache", "In BESH4Cache::BESH4Cache()" << endl);
79 
80  string cacheDir = getCacheDirFromConfig();
81  string prefix = getCachePrefixFromConfig();
82  long size_in_megabytes = getCacheSizeFromConfig();
83 
84  BESDEBUG("cache",
85  "BESH4Cache() - Cache config params: " << cacheDir << ", " << prefix << ", " << size_in_megabytes << endl);
86 
87  // The required params must be present. If initialize() is not called,
88  // then d_cache will stay null and is_available() will return false.
89  // Also, the directory 'path' must exist, or d_cache will be null.
90  if (!cacheDir.empty() && size_in_megabytes > 0) {
91  BESDEBUG("cache", "Before calling initialize function." << endl);
92  initialize(cacheDir, prefix, size_in_megabytes);
93  }
94 
95  BESDEBUG("cache", "Leaving BESH4Cache::BESH4Cache()" << endl);
96 }
97 
101 BESH4Cache *
103 {
104  if (d_enabled && d_instance == 0) {
105  struct stat buf;
106  string cache_dir = getCacheDirFromConfig();
107  if ((stat(cache_dir.c_str(), &buf) == 0) && (buf.st_mode & S_IFDIR)) {
108  try {
109  d_instance = new BESH4Cache();
110 
111  d_enabled = d_instance->cache_enabled();
112  if(!d_enabled){
113  delete d_instance;
114  d_instance = NULL;
115  BESDEBUG("cache", "BESH4Cache::"<<__func__ << "() - " <<
116  "Cache is DISABLED"<< endl);
117  }
118  else {
119 #ifdef HAVE_ATEXIT
120  atexit(delete_instance);
121 #endif
122  BESDEBUG("cache", "BESH4Cache::" << __func__ << "() - " <<
123  "Cache is ENABLED"<< endl);
124  }
125  }
126  catch (BESInternalError &bie) {
127  BESDEBUG("cache",
128  "BESH4Cache::get_instance(): Failed to obtain cache! msg: " << bie.get_message() << endl);
129  }
130  }
131  }
132 
133  return d_instance;
134 }
135 
136 // Check whether the real lat/lon file size is the same as the expected lat/lon size. If not, return false.
137 bool BESH4Cache::is_valid(const string & cache_file_name, const int expected_file_size)
138 {
139 
140  struct stat st;
141  int result = stat(cache_file_name.c_str(), &st);
142  if (result != 0) {
143  string msg = "Cannot check the cached file " + cache_file_name;
144  throw BESInternalError(msg, __FILE__, __LINE__);
145  }
146  if (expected_file_size == st.st_size)
147  return true;
148  else
149  return false;
150 }
151 
152 // This call will try to obtain the read lock.
153 bool BESH4Cache::get_data_from_cache(const string & cache_file_name, const int expected_file_size, int &fd)
154 {
155 #if 0
156  cerr<<"coming to get_data_from_cache "<<endl;
157  BESDEBUG("cache", "In BESH4Cache::get_data_from_cache()" << endl);
158  cerr<<"cache_file_name is "<<cache_file_name <<endl;
159  int fd1;
160  string cache_file_name1 = cache_file_name;
161  get_read_lock(cache_file_name1,fd1);
162 
163  cerr<<"After get_read_lock "<<endl;
164 #endif
165  if (false == get_read_lock(cache_file_name, fd))
166  return false;
167  else if (false == is_valid(cache_file_name, expected_file_size)) {
168  unlock_and_close(cache_file_name);
169  purge_file(cache_file_name);
170  return false;
171  }
172  else
173  return true;
174 }
175 
176 bool BESH4Cache::write_cached_data(const string & cache_file_name, const int expected_file_size,
177  const vector<double> &val)
178 {
179 
180  BESDEBUG("cache", "In BESH4Cache::write_cached_data()" << endl);
181  int fd = 0;
182  bool ret_value = false;
183 
184  // 1. create_and_lock.
185  if (create_and_lock(cache_file_name, fd)) {
186 
187  ssize_t ret_val = 0;
188 
189  // 2. write the file.
190  ret_val = write(fd, &val[0], expected_file_size);
191 
192  // 3. If the written size is not the same as the expected file size, purge the file.
193  if (ret_val != expected_file_size) {
194  if (unlink(cache_file_name.c_str()) != 0) {
195  string msg = "Cannot remove the corrupt cached file " + cache_file_name;
196  throw BESInternalError(msg, __FILE__, __LINE__);
197  }
198 
199  }
200  else {
201  unsigned long long size = update_cache_info(cache_file_name);
202  if (cache_too_big(size)) update_and_purge(cache_file_name);
203  ret_value = true;
204  }
205  // 4. release the lock.
206  unlock_and_close(cache_file_name);
207 
208  }
209 
210  return ret_value;
211 
212 }
213 
214 bool BESH4Cache::write_cached_data2(const string & cache_file_name, const int expected_file_size, const void *buf)
215 {
216 
217  BESDEBUG("cache", "In BESH4Cache::write_cached_data()" << endl);
218  int fd = 0;
219  bool ret_value = false;
220 
221  // 1. create_and_lock.
222  if (create_and_lock(cache_file_name, fd)) {
223 
224  ssize_t ret_val = 0;
225 
226  // 2. write the file.
227  ret_val = write(fd, buf, expected_file_size);
228 
229  // 3. If the written size is not the same as the expected file size, purge the file.
230  if (ret_val != expected_file_size) {
231  if (unlink(cache_file_name.c_str()) != 0) {
232  string msg = "Cannot remove the corrupt cached file " + cache_file_name;
233  throw BESInternalError(msg, __FILE__, __LINE__);
234  }
235 
236  }
237  else {
238  unsigned long long size = update_cache_info(cache_file_name);
239  if (cache_too_big(size)) update_and_purge(cache_file_name);
240  ret_value = true;
241  }
242  // 4. release the lock.
243  unlock_and_close(cache_file_name);
244 
245  }
246 
247  return ret_value;
248 
249 }
250 #if 0
251 void BESH4Cache::dummy_test_func() {
252 
253  cerr<<"BESH4Cache function is fine "<<endl;
254 
255 }
256 
257 string BESH4Cache::get_cache_file_name_h4(const string & src, bool mangle) {
258 
259  return src;
260 }
261 #endif
262 
virtual std::string get_message()
get the error message for this exception
Definition: BESError.h:99
static BESH4Cache * get_instance()
Definition: BESH4MCache.cc:102
exception thrown if internal error encountered