OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESUncompressManager3.cc
Go to the documentation of this file.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #include "BESCache3.h"
37 
38 #include "BESInternalError.h"
39 #include "BESDebug.h"
40 
41 #include "TheBESKeys.h"
42 
43 BESUncompressManager3 *BESUncompressManager3::_instance = 0;
44 
54 BESUncompressManager3::BESUncompressManager3()
55 {
59 }
60 
70 bool BESUncompressManager3::add_method(const string &name, p_bes_uncompress method)
71 {
72  BESUncompressManager3::UCIter i;
73  i = _uncompress_list.find(name);
74  if (i == _uncompress_list.end()) {
75  _uncompress_list[name] = method;
76  return true;
77  }
78  return false;
79 }
80 
90 {
91  BESUncompressManager3::UCIter i;
92  i = _uncompress_list.find(name);
93  if (i != _uncompress_list.end()) {
94  return (*i).second;
95  }
96  return 0;
97 }
98 
131 bool BESUncompressManager3::uncompress(const string &src, string &cfile, BESCache3 *cache)
132 {
133  BESDEBUG( "uncompress2", "uncompress - src: " << src << endl );
134 
135  // All compressed files have a 'dot extension'.
136  string::size_type dot = src.rfind(".");
137  if (dot == string::npos) {
138  BESDEBUG( "uncompress2", "uncompress - no file extension" << endl );
139  return false;
140  }
141 
142  string ext = src.substr(dot + 1, src.length() - dot);
143 
144  // If there's no match for the extension, the file is not compressed and we return false.
145  // Otherwise, 'p' points to a function that decompresses the data.
146  p_bes_uncompress p = find_method(ext);
147  if (!p) {
148  BESDEBUG( "uncompress2", "uncompress - not compressed " << endl );
149  return false;
150  }
151 
152  // Get the name of the file in the cache (either the code finds this file or
153  // or it makes it).
154  cfile = cache->get_cache_file_name(src);
155 
156  try {
157  BESDEBUG( "uncompress2", "uncompress - is cached? " << src << endl );
158 
159  int fd;
160  if (cache->get_read_lock(cfile, fd)) {
161  BESDEBUG( "uncompress", "uncompress - cached hit: " << cfile << endl );
162  return true;
163  }
164 
165  // Now we actually try to decompress the file, given that there's not a decomp'd version
166  // in the cache. First make an empty file and get an exclusive lock on it.
167  if (cache->create_and_lock(cfile, fd)) {
168  BESDEBUG( "uncompress", "uncompress - caching " << cfile << endl );
169 
170  // decompress. Make sure that the decompression function does not close
171  // the file descriptor.
172  p(src, fd);
173 
174  // Change the exclusive lock on the new file to a shared lock. This keeps
175  // other processes from purging the new file and ensures that the reading
176  // process can use it.
177  cache->exclusive_to_shared_lock(fd);
178 
179  // Now update the total cache size info and purge if needed. The new file's
180  // name is passed into the purge method because this process cannot detect its
181  // own lock on the file.
182  unsigned long long size = cache->update_cache_info(cfile);
183  if (cache->cache_too_big(size))
184  cache->update_and_purge(cfile);
185 
186  return true;
187  }
188  else {
189  if (cache->get_read_lock(cfile, fd)) {
190  BESDEBUG( "uncompress", "uncompress - cached hit: " << cfile << endl );
191  return true;
192  }
193  }
194 
195  return false;
196  }
197  catch (...) {
198  BESDEBUG( "uncompress", "caught exception, unlocking cache and re-throw." << endl );
199  cache->unlock_cache();
200  throw;
201  }
202 }
203 
211 void BESUncompressManager3::dump(ostream &strm) const
212 {
213  strm << BESIndent::LMarg << "BESUncompressManager3::dump - (" << (void *) this << ")" << endl;
215  if (_uncompress_list.size()) {
216  strm << BESIndent::LMarg << "registered uncompression methods:" << endl;
218  BESUncompressManager3::UCIter i = _uncompress_list.begin();
219  BESUncompressManager3::UCIter ie = _uncompress_list.end();
220  for (; i != ie; i++) {
221  strm << BESIndent::LMarg << (*i).first << endl;
222  }
224  }
225  else {
226  strm << BESIndent::LMarg << "registered uncompress methods: none" << endl;
227  }
229 }
230 
233 {
234  if (_instance == 0) {
235  _instance = new BESUncompressManager3;
236  }
237  return _instance;
238 }