bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
BESUncompressManager3.cc
1// BESUncompressManager3.cc
2
3// This file is part of bes, A C++ back-end server implementation framework
4// for the OPeNDAP Data Access Protocol.
5
6// Copyright (c) 2012 OPeNDAP, Inc
7// Author: James Gallagher <jgallagher@opendap.org>
8// Patrick West <pwest@ucar.edu> and
9// Jose Garcia <jgarcia@ucar.edu>
10//
11// This library is free software; you can redistribute it and/or
12// modify it under the terms of the GNU Lesser General Public
13// License as published by the Free Software Foundation; either
14// version 2.1 of the License, or (at your option) any later version.
15//
16// This library is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19// Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public
22// License along with this library; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24//
25// You can contact University Corporation for Atmospheric Research at
26// 3080 Center Green Drive, Boulder, CO 80301
27
28#include "config.h"
29
30#include <mutex>
31
32#include <sstream>
33
34using std::istringstream;
35using std::endl;
36using std::ostream;
37using std::string;
38
39#include "BESUncompressManager3.h"
40#include "BESUncompress3GZ.h"
41#include "BESUncompress3BZ2.h"
42#include "BESUncompress3Z.h"
43
44#include "BESFileLockingCache.h"
45
46#include "BESInternalError.h"
47#include "BESDebug.h"
48
49#include "TheBESKeys.h"
50
51BESUncompressManager3 *BESUncompressManager3::d_instance = nullptr;
52static std::once_flag d_euc_init_once;
53
69
70BESUncompressManager3::~BESUncompressManager3() {}
71
81bool BESUncompressManager3::add_method(const string &name, p_bes_uncompress method)
82{
83 std::lock_guard<std::recursive_mutex> lock_me(d_cache_lock_mutex);
84
85 BESUncompressManager3::UCIter i;
86 i = _uncompress_list.find(name);
87 if (i == _uncompress_list.end()) {
88 _uncompress_list[name] = method;
89 return true;
90 }
91 return false;
92}
93
102p_bes_uncompress BESUncompressManager3::find_method(const string &name)
103{
104 std::lock_guard<std::recursive_mutex> lock_me(d_cache_lock_mutex);
105
106 BESUncompressManager3::UCIter i;
107 i = _uncompress_list.find(name);
108 if (i != _uncompress_list.end()) {
109 return (*i).second;
110 }
111 return 0;
112}
113
146bool BESUncompressManager3::uncompress(const string &src, string &cache_file, BESFileLockingCache *cache)
147{
148 std::lock_guard<std::recursive_mutex> lock_me(d_cache_lock_mutex);
149
150 BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - src: " << src << endl );
151
162 if (cache == NULL) {
163 std::ostringstream oss;
164 oss << "BESUncompressManager3::" << __func__ << "() - ";
165 oss << "The supplied Cache object is NULL. Decompression Requires An Operational Cache.";
166 throw BESInternalError(oss.str(), __FILE__, __LINE__);
167 }
168
169 // All compressed files have a 'dot extension'.
170 string::size_type dot = src.rfind(".");
171 if (dot == string::npos) {
172 BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - no file extension" << endl );
173 return false;
174 }
175
176 string ext = src.substr(dot + 1, src.size() - dot);
177
178 // If there's no match for the extension, the file is not compressed and we return false.
179 // Otherwise, 'p' points to a function that uncompresses the data.
180 p_bes_uncompress p = find_method(ext);
181 if (!p) {
182 BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - not compressed " << endl );
183 return false;
184 }
185
186 // Get the name of the file in the cache (either the code finds this file or
187 // it makes it).
188 cache_file = cache->get_cache_file_name(src);
189
190#if 0
191 try {
192 BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - is cached? " << src << endl );
193#endif
194
195 int fd;
196 if (cache->get_read_lock(cache_file, fd)) {
197 BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - cached hit: " << cache_file << endl );
198 return true;
199 }
200
201 // Now we actually try to uncompress the file, given that there's not a decomp'd version
202 // in the cache. First make an empty file and get an exclusive lock on it.
203 if (cache->create_and_lock(cache_file, fd)) {
204 BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - caching " << cache_file << endl );
205
206 // uncompress. Make sure that the decompression function does not close
207 // the file descriptor.
208 p(src, fd);
209
210 // Change the exclusive lock on the new file to a shared lock. This keeps
211 // other processes from purging the new file and ensures that the reading
212 // process can use it.
213 cache->exclusive_to_shared_lock(fd);
214
215 // Now update the total cache size info and purge if needed. The new file's
216 // name is passed into the purge method because this process cannot detect its
217 // own lock on the file.
218 unsigned long long size = cache->update_cache_info(cache_file);
219 if (cache->cache_too_big(size))
220 cache->update_and_purge(cache_file);
221
222 return true;
223 }
224 else {
225 if (cache->get_read_lock(cache_file, fd)) {
226 BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - cached hit: " << cache_file << endl );
227 return true;
228 }
229 }
230
231 return false;
232#if 0
233 }
234 catch (...) {
235 BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - caught exception, unlocking cache and re-throw." << endl );
236 cache->unlock_cache();
237 throw;
238 }
239
240 return false; // gcc warns without this
241#endif
242}
243
251void BESUncompressManager3::dump(ostream &strm) const
252{
253 std::lock_guard<std::recursive_mutex> lock_me(d_cache_lock_mutex);
254
255 strm << BESIndent::LMarg << "BESUncompressManager3::dump - (" << (void *) this << ")" << endl;
256 BESIndent::Indent();
257 if (_uncompress_list.size()) {
258 strm << BESIndent::LMarg << "registered uncompression methods:" << endl;
259 BESIndent::Indent();
260 BESUncompressManager3::UCIter i = _uncompress_list.begin();
261 BESUncompressManager3::UCIter ie = _uncompress_list.end();
262 for (; i != ie; i++) {
263 strm << BESIndent::LMarg << (*i).first << endl;
264 }
265 BESIndent::UnIndent();
266 }
267 else {
268 strm << BESIndent::LMarg << "registered uncompress methods: none" << endl;
269 }
270 BESIndent::UnIndent();
271}
272
274BESUncompressManager3::TheManager()
275{
276 std::call_once(d_euc_init_once,BESUncompressManager3::initialize_instance);
277 return d_instance;
278}
279
280void BESUncompressManager3::initialize_instance() {
281 d_instance = new BESUncompressManager3;
282#ifdef HAVE_ATEXIT
283 atexit(delete_instance);
284#endif
285}
286
287void BESUncompressManager3::delete_instance() {
288 delete d_instance;
289 d_instance = 0;
290}
Implementation of a caching mechanism for compressed data.
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 void exclusive_to_shared_lock(int fd)
Transfer from an exclusive lock to a shared lock.
virtual bool get_read_lock(const std::string &target, int &fd)
Get a read-only lock on the file if it exists.
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.
virtual std::string get_cache_file_name(const std::string &src, bool mangle=true)
exception thrown if internal error encountered
static void uncompress(const std::string &src, int fd)
uncompress a file with the .bz2 file extension
static void uncompress(const std::string &src, int dest_fd)
uncompress a file with the .gz file extension
static void uncompress(const std::string &src, int fd)
uncompress a file with the .gz file extension
List of all registered decompression methods.
BESUncompressManager3()
constructs an uncompression manager adding gz, z, and bz2 uncompression methods by default.
virtual bool add_method(const std::string &name, p_bes_uncompress method)
create_and_lock a uncompress method to the list
virtual p_bes_uncompress find_method(const std::string &name)
returns the uncompression method specified
virtual bool uncompress(const std::string &src, std::string &target, BESFileLockingCache *cache)
If the file 'src' should be uncompressed, do so and return a new file name on the value-result param ...
virtual void dump(std::ostream &strm) const
dumps information about this object