libdap
Updated for version 3.17.0
|
00001 // -*- mode: c++; c-basic-offset:4 -*- 00002 00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00004 // Access Protocol. 00005 00006 // Copyright (c) 2008 OPeNDAP, Inc. 00007 // Author: James Gallagher <jgallagher@opendap.org> 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 // 00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00024 00025 #ifndef _http_cache_table_h 00026 #define _http_cache_table_h 00027 00028 //#define DODS_DEBUG 00029 00030 #include <pthread.h> 00031 00032 #ifdef WIN32 00033 #include <io.h> // stat for win32? 09/05/02 jhrg 00034 #endif 00035 00036 #include <cstring> 00037 00038 #include <string> 00039 #include <vector> 00040 #include <map> 00041 00042 #ifndef _http_cache_h 00043 #include "HTTPCache.h" 00044 #endif 00045 00046 #ifndef _error_h 00047 #include "Error.h" 00048 #endif 00049 00050 #ifndef _internalerr_h 00051 #include "InternalErr.h" 00052 #endif 00053 00054 #ifndef _util_h 00055 #include "util.h" 00056 #endif 00057 00058 #ifndef _debug_h 00059 #include "debug.h" 00060 #endif 00061 00062 //long_to_string(code)); 00063 #define LOCK(m) do { \ 00064 int code = pthread_mutex_lock((m)); \ 00065 if (code != 0) \ 00066 throw InternalErr(__FILE__, __LINE__, string("Mutex lock: ") + strerror(code)); \ 00067 } while(0); 00068 00069 //+ long_to_string(code)); 00070 #define UNLOCK(m) do { \ 00071 int code = pthread_mutex_unlock((m)); \ 00072 if (code != 0) \ 00073 throw InternalErr(__FILE__, __LINE__, string("Mutex unlock: ") + strerror(code)); \ 00074 } while(0); 00075 00076 #define TRYLOCK(m) pthread_mutex_trylock((m)) 00077 #define INIT(m) pthread_mutex_init((m), 0) 00078 #define DESTROY(m) pthread_mutex_destroy((m)) 00079 00080 //using namespace std; 00081 00082 namespace libdap { 00083 00084 int get_hash(const string &url); 00085 00101 class HTTPCacheTable { 00102 public: 00114 struct CacheEntry { 00115 private: 00116 string url; // Location 00117 int hash; 00118 int hits; // Hit counts 00119 string cachename; 00120 00121 string etag; 00122 time_t lm; // Last modified 00123 time_t expires; 00124 time_t date; // From the response header. 00125 time_t age; 00126 time_t max_age; // From Cache-Control 00127 00128 unsigned long size; // Size of cached entity body 00129 bool range; // Range is not currently supported. 10/02/02 jhrg 00130 00131 time_t freshness_lifetime; 00132 time_t response_time; 00133 time_t corrected_initial_age; 00134 00135 bool must_revalidate; 00136 bool no_cache; // This field is not saved in the index. 00137 00138 int readers; 00139 pthread_mutex_t d_response_lock; // set if being read 00140 pthread_mutex_t d_response_write_lock; // set if being written 00141 00142 // Allow HTTPCacheTable methods access and the test class, too 00143 friend class HTTPCacheTable; 00144 friend class HTTPCacheTest; 00145 00146 // Allow access by the functors used in HTTPCacheTable 00147 friend class DeleteCacheEntry; 00148 friend class WriteOneCacheEntry; 00149 friend class DeleteExpired; 00150 friend class DeleteByHits; 00151 friend class DeleteBySize; 00152 00153 public: 00154 string get_cachename() 00155 { 00156 return cachename; 00157 } 00158 string get_etag() 00159 { 00160 return etag; 00161 } 00162 time_t get_lm() 00163 { 00164 return lm; 00165 } 00166 time_t get_expires() 00167 { 00168 return expires; 00169 } 00170 time_t get_max_age() 00171 { 00172 return max_age; 00173 } 00174 void set_size(unsigned long sz) 00175 { 00176 size = sz; 00177 } 00178 time_t get_freshness_lifetime() 00179 { 00180 return freshness_lifetime; 00181 } 00182 time_t get_response_time() 00183 { 00184 return response_time; 00185 } 00186 time_t get_corrected_initial_age() 00187 { 00188 return corrected_initial_age; 00189 } 00190 bool get_must_revalidate() 00191 { 00192 return must_revalidate; 00193 } 00194 void set_no_cache(bool state) 00195 { 00196 no_cache = state; 00197 } 00198 bool is_no_cache() 00199 { 00200 return no_cache; 00201 } 00202 00203 void lock_read_response() 00204 { 00205 DBG(cerr << "Try locking read response... (" << hex << &d_response_lock << dec << ") "); 00206 int status = TRYLOCK(&d_response_lock); 00207 if (status != 0 /*&& status == EBUSY*/) { 00208 // If locked, wait for any writers 00209 LOCK(&d_response_write_lock); 00210 UNLOCK(&d_response_write_lock); 00211 } 00212 00213 readers++; // Record number of readers 00214 00215 DBGN(cerr << "Done" << endl); 00216 00217 } 00218 00219 void unlock_read_response() 00220 { 00221 readers--; 00222 if (readers == 0) { 00223 DBG(cerr << "Unlocking read response... (" << hex << &d_response_lock << dec << ") "); 00224 UNLOCK(&d_response_lock); DBGN(cerr << "Done" << endl); 00225 } 00226 } 00227 00228 void lock_write_response() 00229 { 00230 DBG(cerr << "locking write response... (" << hex << &d_response_lock << dec << ") "); 00231 LOCK(&d_response_lock); 00232 LOCK(&d_response_write_lock); DBGN(cerr << "Done" << endl); 00233 } 00234 00235 void unlock_write_response() 00236 { 00237 DBG(cerr << "Unlocking write response... (" << hex << &d_response_lock << dec << ") "); 00238 UNLOCK(&d_response_write_lock); 00239 UNLOCK(&d_response_lock); DBGN(cerr << "Done" << endl); 00240 } 00241 00242 CacheEntry() : 00243 url(""), hash(-1), hits(0), cachename(""), etag(""), lm(-1), expires(-1), date(-1), age(-1), max_age(-1), size( 00244 0), range(false), freshness_lifetime(0), response_time(0), corrected_initial_age(0), must_revalidate( 00245 false), no_cache(false), readers(0) 00246 { 00247 INIT(&d_response_lock); 00248 INIT(&d_response_write_lock); 00249 } 00250 CacheEntry(const string &u) : 00251 url(u), hash(-1), hits(0), cachename(""), etag(""), lm(-1), expires(-1), date(-1), age(-1), max_age(-1), size( 00252 0), range(false), freshness_lifetime(0), response_time(0), corrected_initial_age(0), must_revalidate( 00253 false), no_cache(false), readers(0) 00254 { 00255 INIT(&d_response_lock); 00256 INIT(&d_response_write_lock); 00257 hash = get_hash(url); 00258 } 00259 }; 00260 00261 // Typedefs for CacheTable. A CacheTable is a vector of vectors of 00262 // CacheEntries. The outer vector is accessed using the hash value. 00263 // Entries with matching hashes occupy successive positions in the inner 00264 // vector (that's how hash collisions are resolved). Search the inner 00265 // vector for a specific match. 00266 typedef vector<CacheEntry *> CacheEntries; 00267 typedef CacheEntries::iterator CacheEntriesIter; 00268 00269 typedef CacheEntries **CacheTable; // Array of pointers to CacheEntries 00270 00271 friend class HTTPCacheTest; 00272 00273 private: 00274 CacheTable d_cache_table; 00275 00276 string d_cache_root; 00277 unsigned int d_block_size; // File block size. 00278 unsigned long d_current_size; 00279 00280 string d_cache_index; 00281 int d_new_entries; 00282 00283 map<FILE *, HTTPCacheTable::CacheEntry *> d_locked_entries; 00284 00285 // Make these private to prevent use 00286 HTTPCacheTable(const HTTPCacheTable &); 00287 HTTPCacheTable &operator=(const HTTPCacheTable &); 00288 HTTPCacheTable(); 00289 00290 CacheTable &get_cache_table() 00291 { 00292 return d_cache_table; 00293 } 00294 00295 CacheEntry *get_locked_entry_from_cache_table(int hash, const string &url); /*const*/ 00296 00297 public: 00298 HTTPCacheTable(const string &cache_root, int block_size); 00299 ~HTTPCacheTable(); 00300 00302 unsigned long get_current_size() const 00303 { 00304 return d_current_size; 00305 } 00306 void set_current_size(unsigned long sz) 00307 { 00308 d_current_size = sz; 00309 } 00310 00311 unsigned int get_block_size() const 00312 { 00313 return d_block_size; 00314 } 00315 void set_block_size(unsigned int sz) 00316 { 00317 d_block_size = sz; 00318 } 00319 00320 int get_new_entries() const 00321 { 00322 return d_new_entries; 00323 } 00324 void increment_new_entries() 00325 { 00326 ++d_new_entries; 00327 } 00328 00329 string get_cache_root() 00330 { 00331 return d_cache_root; 00332 } 00333 void set_cache_root(const string &cr) 00334 { 00335 d_cache_root = cr; 00336 } 00338 00339 void delete_expired_entries(time_t time = 0); 00340 void delete_by_hits(int hits); 00341 void delete_by_size(unsigned int size); 00342 void delete_all_entries(); 00343 00344 bool cache_index_delete(); 00345 bool cache_index_read(); 00346 CacheEntry *cache_index_parse_line(const char *line); 00347 void cache_index_write(); 00348 00349 string create_hash_directory(int hash); 00350 void create_location(CacheEntry *entry); 00351 00352 void add_entry_to_cache_table(CacheEntry *entry); 00353 void remove_cache_entry(HTTPCacheTable::CacheEntry *entry); 00354 00355 void remove_entry_from_cache_table(const string &url); 00356 CacheEntry *get_locked_entry_from_cache_table(const string &url); 00357 CacheEntry *get_write_locked_entry_from_cache_table(const string &url); 00358 00359 void calculate_time(HTTPCacheTable::CacheEntry *entry, int default_expiration, time_t request_time); 00360 void parse_headers(HTTPCacheTable::CacheEntry *entry, unsigned long max_entry_size, const vector<string> &headers); 00361 00362 // These should move back to HTTPCache 00363 void bind_entry_to_data(CacheEntry *entry, FILE *body); 00364 void uncouple_entry_from_data(FILE *body); 00365 bool is_locked_read_responses(); 00366 }; 00367 00368 } // namespace libdap 00369 #endif