HTTPCacheTable.h

Go to the documentation of this file.
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

Generated on Fri Apr 24 22:10:22 2009 for libdap++ by  doxygen 1.4.7