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