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