bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
BESH4MCache.cc
1
2// 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: Kent Yang <myang6@hdfgroup.org>
5// Copyright (c) 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
22using namespace std;
23
24BESH4Cache *BESH4Cache::d_instance = nullptr;
25bool BESH4Cache::d_enabled = true;
26
27const string BESH4Cache::PATH_KEY = "HDF4.Cache.latlon.path";
28const string BESH4Cache::PREFIX_KEY = "HDF4.Cache.latlon.prefix";
29const string BESH4Cache::SIZE_KEY = "HDF4.Cache.latlon.size";
30
31long 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
46string 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
61string 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
76BESH4Cache::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
103{
104 if (d_enabled && d_instance == nullptr) {
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 = nullptr;
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.
137bool BESH4Cache::is_valid(const string & cache_file_name, const int expected_file_size) const
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.
153bool 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
176bool 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.data(), 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
214bool 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
251void BESH4Cache::dummy_test_func() {
252
253 cerr<<"BESH4Cache function is fine "<<endl;
254
255}
256
257string BESH4Cache::get_cache_file_name_h4(const string & src, bool mangle) {
258
259 return src;
260}
261#endif
262
std::string get_message() const
get the error message for this exception
Definition BESError.h:132
void initialize(const std::string &cache_dir, const std::string &prefix, unsigned long long size)
Initialize an instance of FileLockingCache.
virtual void unlock_and_close(const std::string &target)
virtual unsigned long long update_cache_info(const std::string &target)
Update the cache info file to include 'target'.
virtual bool create_and_lock(const std::string &target, int &fd)
Create a file in the cache and lock it for write access.
virtual bool get_read_lock(const std::string &target, int &fd)
Get a read-only lock on the file if it exists.
virtual void purge_file(const std::string &file)
Purge a single file from the cache.
virtual bool cache_too_big(unsigned long long current_size) const
look at the cache size; is it too large? Look at the cache size and see if it is too big.
virtual void update_and_purge(const std::string &new_file)
Purge files from the cache.
static BESH4Cache * get_instance()
exception thrown if internal error encountered