bes  Updated for version 3.17.0
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 <sstream>
29 
30 using std::istringstream;
31 
32 #include "BESUncompressManager3.h"
33 #include "BESUncompress3GZ.h"
34 #include "BESUncompress3BZ2.h"
35 #include "BESUncompress3Z.h"
36 
37 #include "BESFileLockingCache.h"
38 
39 #include "BESInternalError.h"
40 #include "BESDebug.h"
41 
42 #include "TheBESKeys.h"
43 
44 BESUncompressManager3 *BESUncompressManager3::_instance = 0;
45 
55 BESUncompressManager3::BESUncompressManager3()
56 {
60 }
61 
71 bool BESUncompressManager3::add_method(const string &name, p_bes_uncompress method)
72 {
73  BESUncompressManager3::UCIter i;
74  i = _uncompress_list.find(name);
75  if (i == _uncompress_list.end()) {
76  _uncompress_list[name] = method;
77  return true;
78  }
79  return false;
80 }
81 
90 p_bes_uncompress BESUncompressManager3::find_method(const string &name)
91 {
92  BESUncompressManager3::UCIter i;
93  i = _uncompress_list.find(name);
94  if (i != _uncompress_list.end()) {
95  return (*i).second;
96  }
97  return 0;
98 }
99 
132 bool BESUncompressManager3::uncompress(const string &src, string &cfile, BESFileLockingCache *cache)
133 {
134  BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - src: " << src << endl );
135 
136  // All compressed files have a 'dot extension'.
137  string::size_type dot = src.rfind(".");
138  if (dot == string::npos) {
139  BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - no file extension" << endl );
140  return false;
141  }
142 
143  string ext = src.substr(dot + 1, src.length() - dot);
144 
145  // If there's no match for the extension, the file is not compressed and we return false.
146  // Otherwise, 'p' points to a function that uncompresses the data.
147  p_bes_uncompress p = find_method(ext);
148  if (!p) {
149  BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - not compressed " << endl );
150  return false;
151  }
152 
153  // Get the name of the file in the cache (either the code finds this file or
154  // or it makes it).
155  cfile = cache->get_cache_file_name(src);
156 
157  try {
158  BESDEBUG( "uncompress2", "BESUncompressManager3::uncompress() - is cached? " << src << endl );
159 
160  int fd;
161  if (cache->get_read_lock(cfile, fd)) {
162  BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - cached hit: " << cfile << endl );
163  return true;
164  }
165 
166  // Now we actually try to uncompress the file, given that there's not a decomp'd version
167  // in the cache. First make an empty file and get an exclusive lock on it.
168  if (cache->create_and_lock(cfile, fd)) {
169  BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - caching " << cfile << endl );
170 
171  // uncompress. Make sure that the decompression function does not close
172  // the file descriptor.
173  p(src, fd);
174 
175  // Change the exclusive lock on the new file to a shared lock. This keeps
176  // other processes from purging the new file and ensures that the reading
177  // process can use it.
178  cache->exclusive_to_shared_lock(fd);
179 
180  // Now update the total cache size info and purge if needed. The new file's
181  // name is passed into the purge method because this process cannot detect its
182  // own lock on the file.
183  unsigned long long size = cache->update_cache_info(cfile);
184  if (cache->cache_too_big(size))
185  cache->update_and_purge(cfile);
186 
187  return true;
188  }
189  else {
190  if (cache->get_read_lock(cfile, fd)) {
191  BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - cached hit: " << cfile << endl );
192  return true;
193  }
194  }
195 
196  return false;
197  }
198  catch (...) {
199  BESDEBUG( "uncompress", "BESUncompressManager3::uncompress() - caught exception, unlocking cache and re-throw." << endl );
200  cache->unlock_cache();
201  throw;
202  }
203 
204  return false; // gcc warns without this
205 }
206 
214 void BESUncompressManager3::dump(ostream &strm) const
215 {
216  strm << BESIndent::LMarg << "BESUncompressManager3::dump - (" << (void *) this << ")" << endl;
217  BESIndent::Indent();
218  if (_uncompress_list.size()) {
219  strm << BESIndent::LMarg << "registered uncompression methods:" << endl;
220  BESIndent::Indent();
221  BESUncompressManager3::UCIter i = _uncompress_list.begin();
222  BESUncompressManager3::UCIter ie = _uncompress_list.end();
223  for (; i != ie; i++) {
224  strm << BESIndent::LMarg << (*i).first << endl;
225  }
226  BESIndent::UnIndent();
227  }
228  else {
229  strm << BESIndent::LMarg << "registered uncompress methods: none" << endl;
230  }
231  BESIndent::UnIndent();
232 }
233 
235 BESUncompressManager3::TheManager()
236 {
237  if (_instance == 0) {
238  _instance = new BESUncompressManager3;
239  }
240  return _instance;
241 }
virtual bool create_and_lock(const string &target, int &fd)
Create a file in the cache and lock it for write access. If the file does not exist, make it, open it for read-write access and get an exclusive lock on it. The locking operation blocks, although that should never happen.
static void uncompress(const string &src, int fd)
uncompress a file with the .gz file extension
virtual bool uncompress(const string &src, string &target, BESFileLockingCache *cache)
If the file &#39;src&#39; should be uncompressed, do so and return a new file name on the value-result param ...
Implementation of a caching mechanism for compressed data. This cache uses simple advisory locking fo...
List of all registered decompression methods.
virtual void dump(ostream &strm) const
dumps information about this object
virtual p_bes_uncompress find_method(const string &name)
returns the uncompression method specified
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 bool get_read_lock(const string &target, int &fd)
Get a read-only lock on the file if it exists.
virtual void update_and_purge(const string &new_file)
Purge files from the cache.
virtual unsigned long long update_cache_info(const string &target)
Update the cache info file to include &#39;target&#39;.
virtual void exclusive_to_shared_lock(int fd)
Transfer from an exclusive lock to a shared lock. If the file has an exclusive write lock on it...
static void uncompress(const string &src, int dest_fd)
uncompress a file with the .gz file extension
virtual bool add_method(const string &name, p_bes_uncompress method)
create_and_lock a uncompress method to the list
static void uncompress(const string &src, int fd)
uncompress a file with the .bz2 file extension