libdap++ Updated for version 3.8.2

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 
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