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 _error_h 00042 #include "Error.h" 00043 #endif 00044 00045 #ifndef _internalerr_h 00046 #include "InternalErr.h" 00047 #endif 00048 00049 #ifndef _debug_h 00050 #include "debug.h" 00051 #endif 00052 00053 #define LOCK(m) pthread_mutex_lock((m)) 00054 #define TRYLOCK(m) pthread_mutex_trylock((m)) 00055 #define UNLOCK(m) pthread_mutex_unlock((m)) 00056 #define INIT(m) pthread_mutex_init((m), 0) 00057 #define DESTROY(m) pthread_mutex_destroy((m)) 00058 00059 using namespace std; 00060 00061 namespace libdap 00062 { 00063 00064 int get_hash(const string &url); 00065 00081 class HTTPCacheTable { 00082 public: 00094 struct CacheEntry 00095 { 00096 private: 00097 string url; // Location 00098 int hash; 00099 int hits; // Hit counts 00100 string cachename; 00101 00102 string etag; 00103 time_t lm; // Last modified 00104 time_t expires; 00105 time_t date; // From the response header. 00106 time_t age; 00107 time_t max_age; // From Cache-Control 00108 00109 unsigned long size; // Size of cached entity body 00110 bool range; // Range is not currently supported. 10/02/02 jhrg 00111 00112 time_t freshness_lifetime; 00113 time_t response_time; 00114 time_t corrected_initial_age; 00115 00116 bool must_revalidate; 00117 bool no_cache; // This field is not saved in the index. 00118 00119 int readers; 00120 pthread_mutex_t d_response_lock; // set if being read 00121 pthread_mutex_t d_response_write_lock; // set if being written 00122 #if 0 00123 // This lock prevents access to the fields of a CacheEntry. Might not 00124 // be needed. 00125 pthread_mutex_t d_lock; 00126 #endif 00127 // Allow HTTPCacheTable methods access and the test class, too 00128 friend class HTTPCacheTable; 00129 friend class HTTPCacheTest; 00130 00131 // Allow access by the fucntors used in HTTPCacheTable 00132 friend class DeleteCacheEntry; 00133 friend class WriteOneCacheEntry; 00134 friend class DeleteExpired; 00135 friend class DeleteByHits; 00136 friend class DeleteBySize; 00137 00138 public: 00139 string get_cachename() { 00140 return cachename; 00141 } 00142 string get_etag() { 00143 return etag; 00144 } 00145 time_t get_lm() { 00146 return lm; 00147 } 00148 time_t get_expires() { 00149 return expires; 00150 } 00151 time_t get_max_age() { 00152 return max_age; 00153 } 00154 void set_size(unsigned long sz) { 00155 size = sz; 00156 } 00157 time_t get_freshness_lifetime() { 00158 return freshness_lifetime; 00159 } 00160 time_t get_response_time() { 00161 return response_time; 00162 } 00163 time_t get_corrected_initial_age() { 00164 return corrected_initial_age; 00165 } 00166 bool get_must_revalidate() { 00167 return must_revalidate; 00168 } 00169 void set_no_cache(bool state) { 00170 no_cache = state; 00171 } 00172 bool is_no_cache() { return no_cache; } 00173 #if 0 00174 void lock() { 00175 DBG(cerr << "Locking entry... (" << hex << &d_lock << dec << ") "); 00176 LOCK(&d_lock); 00177 DBGN(cerr << "Done" << endl); 00178 } 00179 void unlock() { 00180 DBG(cerr << "Unlocking entry... (" << hex << &d_lock << dec << ") "); 00181 UNLOCK(&d_lock); 00182 DBGN(cerr << "Done" << endl); 00183 } 00184 pthread_mutex_t &get_lock() { return d_lock; } 00185 #endif 00186 void lock_read_response() { 00187 DBG(cerr << "Try locking read response... (" << hex << &d_response_lock << dec << ") "); 00188 int status = TRYLOCK(&d_response_lock); 00189 if (status != 0 /*&& status == EBUSY*/) { 00190 // If locked, wait for any writers 00191 LOCK(&d_response_write_lock); 00192 UNLOCK(&d_response_write_lock); 00193 } 00194 DBGN(cerr << "Done" << endl); 00195 readers++; // REcord number of readers 00196 } 00197 00198 void unlock_read_response() { 00199 readers--; 00200 if (readers == 0) { 00201 DBG(cerr << "Unlocking read response... (" << hex << &d_response_lock << dec << ") "); 00202 UNLOCK(&d_response_lock); 00203 DBGN(cerr << "Done" << endl); 00204 } 00205 } 00206 00207 void lock_write_response() { 00208 DBG(cerr << "locking write response... (" << hex << &d_response_lock << dec << ") "); 00209 LOCK(&d_response_lock); 00210 LOCK(&d_response_write_lock); 00211 DBGN(cerr << "Done" << endl); 00212 } 00213 00214 void unlock_write_response() { 00215 DBG(cerr << "Unlocking write response... (" << hex << &d_response_lock << dec << ") "); 00216 UNLOCK(&d_response_write_lock); 00217 UNLOCK(&d_response_lock); 00218 DBGN(cerr << "Done" << endl); 00219 } 00220 00221 CacheEntry() : 00222 url(""), hash(-1), hits(0), cachename(""), etag(""), lm(-1), 00223 expires(-1), date(-1), age(-1), max_age(-1), size(0), 00224 range(false), freshness_lifetime(0), response_time(0), 00225 corrected_initial_age(0), must_revalidate(false), 00226 no_cache(false), readers(0) { 00227 INIT(&d_response_lock); 00228 INIT(&d_response_write_lock); 00229 #if 0 00230 INIT(&d_lock); 00231 #endif 00232 } 00233 CacheEntry(const string &u) : 00234 url(u), hash(-1), hits(0), cachename(""), etag(""), lm(-1), 00235 expires(-1), date(-1), age(-1), max_age(-1), size(0), 00236 range(false), freshness_lifetime(0), response_time(0), 00237 corrected_initial_age(0), must_revalidate(false), 00238 no_cache(false), readers(0) { 00239 INIT(&d_response_lock); 00240 INIT(&d_response_write_lock); 00241 #if 0 00242 INIT(&d_lock); 00243 #endif 00244 hash = get_hash(url); 00245 } 00246 }; 00247 00248 // Typedefs for CacheTable. A CacheTable is a vector of vectors of 00249 // CacheEntries. The outer vector is accessed using the hash value. 00250 // Entries with matching hashes occupy successive positions in the inner 00251 // vector (that's how hash collisions are resolved). Search the inner 00252 // vector for a specific match. 00253 typedef vector<CacheEntry *> CacheEntries; 00254 typedef CacheEntries::iterator CacheEntriesIter; 00255 00256 typedef CacheEntries **CacheTable;// Array of pointers to CacheEntries 00257 00258 friend class HTTPCacheTest; 00259 00260 private: 00261 CacheTable d_cache_table; 00262 00263 string d_cache_root; 00264 unsigned int d_block_size; // File block size. 00265 unsigned long d_current_size; 00266 00267 string d_cache_index; 00268 int d_new_entries; 00269 00270 map<FILE *, HTTPCacheTable::CacheEntry *> d_locked_entries; 00271 00272 // Make these private to prevent use 00273 HTTPCacheTable(const HTTPCacheTable &) { 00274 throw InternalErr(__FILE__, __LINE__, "unimplemented"); 00275 } 00276 00277 HTTPCacheTable &operator=(const HTTPCacheTable &) { 00278 throw InternalErr(__FILE__, __LINE__, "unimplemented"); 00279 } 00280 00281 HTTPCacheTable() { 00282 throw InternalErr(__FILE__, __LINE__, "unimplemented"); 00283 } 00284 00285 CacheTable &get_cache_table() { return d_cache_table; } 00286 CacheEntry *get_locked_entry_from_cache_table(int hash, const string &url); /*const*/ 00287 00288 public: 00289 HTTPCacheTable(const string &cache_root, int block_size); 00290 ~HTTPCacheTable(); 00291 00293 unsigned long get_current_size() const { return d_current_size; } 00294 void set_current_size(unsigned long sz) { d_current_size = sz; } 00295 00296 unsigned int get_block_size() const { return d_block_size; } 00297 void set_block_size(unsigned int sz) { d_block_size = sz; } 00298 00299 int get_new_entries() const { return d_new_entries; } 00300 void increment_new_entries() { ++d_new_entries; } 00301 00302 string get_cache_root() { return d_cache_root; } 00303 void set_cache_root(const string &cr) { d_cache_root = cr; } 00305 00306 void delete_expired_entries(time_t time = 0); 00307 void delete_by_hits(int hits); 00308 void delete_by_size(unsigned int size); 00309 void delete_all_entries(); 00310 00311 bool cache_index_delete(); 00312 bool cache_index_read(); 00313 CacheEntry *cache_index_parse_line(const char *line); 00314 void cache_index_write(); 00315 00316 string create_hash_directory(int hash); 00317 void create_location(CacheEntry *entry); 00318 00319 void add_entry_to_cache_table(CacheEntry *entry); 00320 void remove_cache_entry(HTTPCacheTable::CacheEntry *entry); 00321 00322 void remove_entry_from_cache_table(const string &url); 00323 CacheEntry *get_locked_entry_from_cache_table(const string &url); 00324 CacheEntry *get_write_locked_entry_from_cache_table(const string &url); 00325 00326 void calculate_time(HTTPCacheTable::CacheEntry *entry, 00327 int default_expiration, time_t request_time); 00328 void parse_headers(HTTPCacheTable::CacheEntry *entry, 00329 unsigned long max_entry_size, const vector<string> &headers); 00330 00331 // These should move back to HTTPCache 00332 void bind_entry_to_data(CacheEntry *entry, FILE *body); 00333 void uncouple_entry_from_data(FILE *body); 00334 bool is_locked_read_responses(); 00335 }; 00336 00337 } // namespace libdap 00338 #endif