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 00123 // Allow HTTPCacheTable methods access and the test class, too 00124 friend class HTTPCacheTable; 00125 friend class HTTPCacheTest; 00126 00127 // Allow access by the fucntors used in HTTPCacheTable 00128 friend class DeleteCacheEntry; 00129 friend class WriteOneCacheEntry; 00130 friend class DeleteExpired; 00131 friend class DeleteByHits; 00132 friend class DeleteBySize; 00133 00134 public: 00135 string get_cachename() { 00136 return cachename; 00137 } 00138 string get_etag() { 00139 return etag; 00140 } 00141 time_t get_lm() { 00142 return lm; 00143 } 00144 time_t get_expires() { 00145 return expires; 00146 } 00147 time_t get_max_age() { 00148 return max_age; 00149 } 00150 void set_size(unsigned long sz) { 00151 size = sz; 00152 } 00153 time_t get_freshness_lifetime() { 00154 return freshness_lifetime; 00155 } 00156 time_t get_response_time() { 00157 return response_time; 00158 } 00159 time_t get_corrected_initial_age() { 00160 return corrected_initial_age; 00161 } 00162 bool get_must_revalidate() { 00163 return must_revalidate; 00164 } 00165 void set_no_cache(bool state) { 00166 no_cache = state; 00167 } 00168 bool is_no_cache() { return no_cache; } 00169 00170 void lock_read_response() { 00171 DBG(cerr << "Try locking read response... (" << hex << &d_response_lock << dec << ") "); 00172 int status = TRYLOCK(&d_response_lock); 00173 if (status != 0 /*&& status == EBUSY*/) { 00174 // If locked, wait for any writers 00175 LOCK(&d_response_write_lock); 00176 UNLOCK(&d_response_write_lock); 00177 } 00178 DBGN(cerr << "Done" << endl); 00179 readers++; // REcord number of readers 00180 } 00181 00182 void unlock_read_response() { 00183 readers--; 00184 if (readers == 0) { 00185 DBG(cerr << "Unlocking read response... (" << hex << &d_response_lock << dec << ") "); 00186 UNLOCK(&d_response_lock); 00187 DBGN(cerr << "Done" << endl); 00188 } 00189 } 00190 00191 void lock_write_response() { 00192 DBG(cerr << "locking write response... (" << hex << &d_response_lock << dec << ") "); 00193 LOCK(&d_response_lock); 00194 LOCK(&d_response_write_lock); 00195 DBGN(cerr << "Done" << endl); 00196 } 00197 00198 void unlock_write_response() { 00199 DBG(cerr << "Unlocking write response... (" << hex << &d_response_lock << dec << ") "); 00200 UNLOCK(&d_response_write_lock); 00201 UNLOCK(&d_response_lock); 00202 DBGN(cerr << "Done" << endl); 00203 } 00204 00205 CacheEntry() : 00206 url(""), hash(-1), hits(0), cachename(""), etag(""), lm(-1), 00207 expires(-1), date(-1), age(-1), max_age(-1), size(0), 00208 range(false), freshness_lifetime(0), response_time(0), 00209 corrected_initial_age(0), must_revalidate(false), 00210 no_cache(false), readers(0) { 00211 INIT(&d_response_lock); 00212 INIT(&d_response_write_lock); 00213 } 00214 CacheEntry(const string &u) : 00215 url(u), hash(-1), hits(0), cachename(""), etag(""), lm(-1), 00216 expires(-1), date(-1), age(-1), max_age(-1), size(0), 00217 range(false), freshness_lifetime(0), response_time(0), 00218 corrected_initial_age(0), must_revalidate(false), 00219 no_cache(false), readers(0) { 00220 INIT(&d_response_lock); 00221 INIT(&d_response_write_lock); 00222 hash = get_hash(url); 00223 } 00224 }; 00225 00226 // Typedefs for CacheTable. A CacheTable is a vector of vectors of 00227 // CacheEntries. The outer vector is accessed using the hash value. 00228 // Entries with matching hashes occupy successive positions in the inner 00229 // vector (that's how hash collisions are resolved). Search the inner 00230 // vector for a specific match. 00231 typedef vector<CacheEntry *> CacheEntries; 00232 typedef CacheEntries::iterator CacheEntriesIter; 00233 00234 typedef CacheEntries **CacheTable;// Array of pointers to CacheEntries 00235 00236 friend class HTTPCacheTest; 00237 00238 private: 00239 CacheTable d_cache_table; 00240 00241 string d_cache_root; 00242 unsigned int d_block_size; // File block size. 00243 unsigned long d_current_size; 00244 00245 string d_cache_index; 00246 int d_new_entries; 00247 00248 map<FILE *, HTTPCacheTable::CacheEntry *> d_locked_entries; 00249 00250 // Make these private to prevent use 00251 HTTPCacheTable(const HTTPCacheTable &) { 00252 throw InternalErr(__FILE__, __LINE__, "unimplemented"); 00253 } 00254 00255 HTTPCacheTable &operator=(const HTTPCacheTable &) { 00256 throw InternalErr(__FILE__, __LINE__, "unimplemented"); 00257 } 00258 00259 HTTPCacheTable() { 00260 throw InternalErr(__FILE__, __LINE__, "unimplemented"); 00261 } 00262 00263 CacheTable &get_cache_table() { return d_cache_table; } 00264 CacheEntry *get_locked_entry_from_cache_table(int hash, const string &url); /*const*/ 00265 00266 public: 00267 HTTPCacheTable(const string &cache_root, int block_size); 00268 ~HTTPCacheTable(); 00269 00271 unsigned long get_current_size() const { return d_current_size; } 00272 void set_current_size(unsigned long sz) { d_current_size = sz; } 00273 00274 unsigned int get_block_size() const { return d_block_size; } 00275 void set_block_size(unsigned int sz) { d_block_size = sz; } 00276 00277 int get_new_entries() const { return d_new_entries; } 00278 void increment_new_entries() { ++d_new_entries; } 00279 00280 string get_cache_root() { return d_cache_root; } 00281 void set_cache_root(const string &cr) { d_cache_root = cr; } 00283 00284 void delete_expired_entries(time_t time = 0); 00285 void delete_by_hits(int hits); 00286 void delete_by_size(unsigned int size); 00287 void delete_all_entries(); 00288 00289 bool cache_index_delete(); 00290 bool cache_index_read(); 00291 CacheEntry *cache_index_parse_line(const char *line); 00292 void cache_index_write(); 00293 00294 string create_hash_directory(int hash); 00295 void create_location(CacheEntry *entry); 00296 00297 void add_entry_to_cache_table(CacheEntry *entry); 00298 void remove_cache_entry(HTTPCacheTable::CacheEntry *entry); 00299 00300 void remove_entry_from_cache_table(const string &url); 00301 CacheEntry *get_locked_entry_from_cache_table(const string &url); 00302 CacheEntry *get_write_locked_entry_from_cache_table(const string &url); 00303 00304 void calculate_time(HTTPCacheTable::CacheEntry *entry, 00305 int default_expiration, time_t request_time); 00306 void parse_headers(HTTPCacheTable::CacheEntry *entry, 00307 unsigned long max_entry_size, const vector<string> &headers); 00308 00309 // These should move back to HTTPCache 00310 void bind_entry_to_data(CacheEntry *entry, FILE *body); 00311 void uncouple_entry_from_data(FILE *body); 00312 bool is_locked_read_responses(); 00313 }; 00314 00315 } // namespace libdap 00316 #endif