00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef _http_cache_table_h
00027 #define _http_cache_table_h
00028
00029
00030
00031 #include <pthread.h>
00032
00033 #ifdef WIN32
00034 #include <io.h>
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;
00098 int hash;
00099 int hits;
00100 string cachename;
00101
00102 string etag;
00103 time_t lm;
00104 time_t expires;
00105 time_t date;
00106 time_t age;
00107 time_t max_age;
00108
00109 unsigned long size;
00110 bool range;
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;
00118
00119 int readers;
00120 pthread_mutex_t d_response_lock;
00121 pthread_mutex_t d_response_write_lock;
00122 #if 0
00123
00124
00125 pthread_mutex_t d_lock;
00126 #endif
00127
00128 friend class HTTPCacheTable;
00129 friend class HTTPCacheTest;
00130
00131
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 ) {
00190
00191 LOCK(&d_response_write_lock);
00192 UNLOCK(&d_response_write_lock);
00193 }
00194 DBGN(cerr << "Done" << endl);
00195 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
00249
00250
00251
00252
00253 typedef vector<CacheEntry *> CacheEntries;
00254 typedef CacheEntries::iterator CacheEntriesIter;
00255
00256 typedef CacheEntries **CacheTable;
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;
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
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);
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
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 }
00338 #endif