OPeNDAP Hyrax Back End Server (BES)
Updated for version 3.8.3
|
00001 // BESUncompressManager.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include <sstream> 00034 00035 using std::istringstream ; 00036 00037 #include "BESUncompressManager.h" 00038 #include "BESUncompressGZ.h" 00039 #include "BESUncompressBZ2.h" 00040 #include "BESUncompressZ.h" 00041 #include "BESCache.h" 00042 #include "BESInternalError.h" 00043 #include "BESDebug.h" 00044 #include "TheBESKeys.h" 00045 00046 BESUncompressManager *BESUncompressManager::_instance = 0 ; 00047 00057 BESUncompressManager::BESUncompressManager() 00058 { 00059 add_method( "gz", BESUncompressGZ::uncompress ) ; 00060 add_method( "bz2", BESUncompressBZ2::uncompress ) ; 00061 add_method( "z", BESUncompressZ::uncompress ) ; 00062 00063 bool found = false ; 00064 string key = "BES.Uncompress.Retry" ; 00065 string val ; 00066 TheBESKeys::TheKeys()->get_value( key, val, found ) ; 00067 if( !found || val.empty() ) 00068 { 00069 _retry = 2000 ; 00070 } 00071 else 00072 { 00073 istringstream is( val ) ; 00074 is >> _retry ; 00075 } 00076 00077 key = "BES.Uncompress.NumTries" ; 00078 val = "" ; 00079 TheBESKeys::TheKeys()->get_value( key, val, found ) ; 00080 if( !found || val.empty() ) 00081 { 00082 _num_tries = 10 ; 00083 } 00084 else 00085 { 00086 istringstream is( val ) ; 00087 is >> _num_tries ; 00088 } 00089 } 00090 00100 bool 00101 BESUncompressManager::add_method( const string &name, 00102 p_bes_uncompress method ) 00103 { 00104 BESUncompressManager::UCIter i ; 00105 i = _uncompress_list.find( name ) ; 00106 if( i == _uncompress_list.end() ) 00107 { 00108 _uncompress_list[name] = method ; 00109 return true ; 00110 } 00111 return false ; 00112 } 00113 00122 bool 00123 BESUncompressManager::remove_method( const string &name ) 00124 { 00125 BESUncompressManager::UIter i ; 00126 i = _uncompress_list.find( name ) ; 00127 if( i != _uncompress_list.end() ) 00128 { 00129 _uncompress_list.erase( i ) ; 00130 return true ; 00131 } 00132 return false ; 00133 } 00134 00143 p_bes_uncompress 00144 BESUncompressManager::find_method( const string &name ) 00145 { 00146 BESUncompressManager::UCIter i ; 00147 i = _uncompress_list.find( name ) ; 00148 if( i != _uncompress_list.end() ) 00149 { 00150 return (*i).second ; 00151 } 00152 return 0 ; 00153 } 00154 00160 string 00161 BESUncompressManager::get_method_names() 00162 { 00163 string ret ; 00164 bool first_name = true ; 00165 BESUncompressManager::UCIter i = _uncompress_list.begin() ; 00166 for( ; i != _uncompress_list.end(); i++ ) 00167 { 00168 if( !first_name ) 00169 ret += ", " ; 00170 ret += (*i).first ; 00171 first_name = false ; 00172 } 00173 return ret ; 00174 } 00175 00212 bool 00213 BESUncompressManager::uncompress( const string &src, string &target, 00214 BESCache &cache ) 00215 { 00216 BESDEBUG( "bes", "BESUncompressManager::uncompress - src = " << src << endl ) ; 00217 string::size_type dot = src.rfind( "." ) ; 00218 if( dot != string::npos ) 00219 { 00220 string ext = src.substr( dot+1, src.length() - dot ) ; 00221 // Why fold the extension to lowercase? jhrg 5/9/07 00222 // The extension (Z, gz, bz2, GZ, BZ2, z) is used to determine which 00223 // uncompression engine to use. It is compared to the list, which is 00224 // all lower case. pcw 2/22/08 00225 for( int i = 0; i < static_cast<int>(ext.length()); i++ ) 00226 { 00227 ext[i] = tolower( ext[i] ) ; 00228 } 00229 00230 // if we find the method for this file then use it. If we don't find 00231 // it then assume that the file is not compressed and simply return 00232 // the src file at the end of the method. 00233 p_bes_uncompress p = find_method( ext ) ; 00234 if( p ) 00235 { 00236 // the file is compressed so we either need to uncompress it or 00237 // we need to tell if it is already cached. To do this, lock the 00238 // cache so no one else can do anything 00239 if( cache.lock( _retry, _num_tries ) ) 00240 { 00241 try 00242 { 00243 // before calling uncompress on the file, see if the file 00244 // has already been cached. If it has, then simply return 00245 // the target, no need to cache. 00246 BESDEBUG( "bes", "BESUncompressManager::uncompress - is cached? " << src << endl ) ; 00247 if( cache.is_cached( src, target ) ) 00248 { 00249 BESDEBUG( "bes", "BESUncompressManager::uncompress - " << "is cached " << target << endl ) ; 00250 cache.unlock() ; 00251 return true ; 00252 } 00253 00254 // the file is not cached, so we need to uncompress the 00255 // file. First determine if there is enough space in 00256 // the cache to uncompress the file 00257 BESDEBUG( "bes", "BESUncompressManager::uncompress - " << "purging cache" << endl ) ; 00258 cache.purge() ; 00259 00260 // Now that we have some room ... uncompress the file 00261 BESDEBUG( "bes", "BESUncompressManager::uncompress - " 00262 << "uncompress to " << target 00263 << " using " << ext << " uncompression" 00264 << endl ) ; 00265 00266 // we are now done in the cache, unlock it 00267 cache.unlock() ; 00268 00269 // MPJ: Is this safe to call after unlock? 00270 // We just unlocked the cache before we 00271 // decompress the file, so the is_cached call may fail 00272 // for another call while this is occurring 00273 // and spawn another decompress overwriting the other? 00274 // Or will another coming along see the unfinished 00275 // decompressed file and complain? 00276 p( src, target ) ; 00277 return true ; 00278 } 00279 catch( BESError & ) 00280 { 00281 // a problem in the cache, unlock it and re-throw the 00282 // exception 00283 cache.unlock() ; 00284 throw ; 00285 } 00286 catch( ... ) 00287 { 00288 // an unknown problem in the cache, unlock it and throw a 00289 // BES exception 00290 cache.unlock() ; 00291 string err = (string)"Problem working with the cache, " 00292 + "unknown error" ; 00293 throw BESInternalError( err, __FILE__,__LINE__); 00294 } 00295 } 00296 else 00297 { 00298 string err = "Unable to lock the cache " 00299 + cache.cache_dir() ; 00300 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00301 } 00302 } 00303 else 00304 { 00305 BESDEBUG( "bes", "BESUncompressManager::uncompress - not compressed " << endl ) ; 00306 } 00307 } 00308 else 00309 { 00310 BESDEBUG( "bes", "BESUncompressmanager::uncompress - not file extension" << endl ) ; 00311 #if 0 00312 // This could just mean that there is a README file here, so just 00313 // return the src file name and let the system run its course. 00314 string err = "Unable to determine type of file from " 00315 + src ; 00316 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00317 #endif 00318 } 00319 00320 return false ; 00321 } 00322 00330 void 00331 BESUncompressManager::dump( ostream &strm ) const 00332 { 00333 strm << BESIndent::LMarg << "BESUncompressManager::dump - (" 00334 << (void *)this << ")" << endl ; 00335 BESIndent::Indent() ; 00336 if( _uncompress_list.size() ) 00337 { 00338 strm << BESIndent::LMarg << "registered uncompression methods:" << endl; 00339 BESIndent::Indent() ; 00340 BESUncompressManager::UCIter i = _uncompress_list.begin() ; 00341 BESUncompressManager::UCIter ie = _uncompress_list.end() ; 00342 for( ; i != ie; i++ ) 00343 { 00344 strm << BESIndent::LMarg << (*i).first << endl ; 00345 } 00346 BESIndent::UnIndent() ; 00347 } 00348 else 00349 { 00350 strm << BESIndent::LMarg << "registered uncompress methods: none" << endl ; 00351 } 00352 BESIndent::UnIndent() ; 00353 } 00354 00355 BESUncompressManager * 00356 BESUncompressManager::TheManager() 00357 { 00358 if( _instance == 0 ) 00359 { 00360 _instance = new BESUncompressManager ; 00361 } 00362 return _instance ; 00363 }