libdap++  Updated for version 3.8.2
HTTPCacheTable.h
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2008 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 #ifndef _http_cache_table_h
27 #define _http_cache_table_h
28 
29 //#define DODS_DEBUG
30 
31 #include <pthread.h>
32 
33 #ifdef WIN32
34 #include <io.h> // stat for win32? 09/05/02 jhrg
35 #endif
36 
37 #include <string>
38 #include <vector>
39 #include <map>
40 
41 #ifndef _error_h
42 #include "Error.h"
43 #endif
44 
45 #ifndef _internalerr_h
46 #include "InternalErr.h"
47 #endif
48 
49 #ifndef _debug_h
50 #include "debug.h"
51 #endif
52 
53 #define LOCK(m) pthread_mutex_lock((m))
54 #define TRYLOCK(m) pthread_mutex_trylock((m))
55 #define UNLOCK(m) pthread_mutex_unlock((m))
56 #define INIT(m) pthread_mutex_init((m), 0)
57 #define DESTROY(m) pthread_mutex_destroy((m))
58 
59 using namespace std;
60 
61 namespace libdap
62 {
63 
64 int get_hash(const string &url);
65 
82 public:
94  struct CacheEntry
95  {
96  private:
97  string url; // Location
98  int hash;
99  int hits; // Hit counts
100  string cachename;
101 
102  string etag;
103  time_t lm; // Last modified
104  time_t expires;
105  time_t date; // From the response header.
106  time_t age;
107  time_t max_age; // From Cache-Control
108 
109  unsigned long size; // Size of cached entity body
110  bool range; // Range is not currently supported. 10/02/02 jhrg
111 
112  time_t freshness_lifetime;
113  time_t response_time;
114  time_t corrected_initial_age;
115 
116  bool must_revalidate;
117  bool no_cache; // This field is not saved in the index.
118 
119  int readers;
120  pthread_mutex_t d_response_lock; // set if being read
121  pthread_mutex_t d_response_write_lock; // set if being written
122 
123  // Allow HTTPCacheTable methods access and the test class, too
124  friend class HTTPCacheTable;
125  friend class HTTPCacheTest;
126 
127  // Allow access by the fucntors used in HTTPCacheTable
128  friend class DeleteCacheEntry;
129  friend class WriteOneCacheEntry;
130  friend class DeleteExpired;
131  friend class DeleteByHits;
132  friend class DeleteBySize;
133 
134  public:
135  string get_cachename() {
136  return cachename;
137  }
138  string get_etag() {
139  return etag;
140  }
141  time_t get_lm() {
142  return lm;
143  }
144  time_t get_expires() {
145  return expires;
146  }
147  time_t get_max_age() {
148  return max_age;
149  }
150  void set_size(unsigned long sz) {
151  size = sz;
152  }
154  return freshness_lifetime;
155  }
156  time_t get_response_time() {
157  return response_time;
158  }
160  return corrected_initial_age;
161  }
163  return must_revalidate;
164  }
165  void set_no_cache(bool state) {
166  no_cache = state;
167  }
168  bool is_no_cache() { return no_cache; }
169 
171  DBG(cerr << "Try locking read response... (" << hex << &d_response_lock << dec << ") ");
172  int status = TRYLOCK(&d_response_lock);
173  if (status != 0 /*&& status == EBUSY*/) {
174  // If locked, wait for any writers
175  LOCK(&d_response_write_lock);
176  UNLOCK(&d_response_write_lock);
177  }
178  DBGN(cerr << "Done" << endl);
179  readers++; // REcord number of readers
180  }
181 
183  readers--;
184  if (readers == 0) {
185  DBG(cerr << "Unlocking read response... (" << hex << &d_response_lock << dec << ") ");
186  UNLOCK(&d_response_lock);
187  DBGN(cerr << "Done" << endl);
188  }
189  }
190 
192  DBG(cerr << "locking write response... (" << hex << &d_response_lock << dec << ") ");
193  LOCK(&d_response_lock);
194  LOCK(&d_response_write_lock);
195  DBGN(cerr << "Done" << endl);
196  }
197 
199  DBG(cerr << "Unlocking write response... (" << hex << &d_response_lock << dec << ") ");
200  UNLOCK(&d_response_write_lock);
201  UNLOCK(&d_response_lock);
202  DBGN(cerr << "Done" << endl);
203  }
204 
206  url(""), hash(-1), hits(0), cachename(""), etag(""), lm(-1),
207  expires(-1), date(-1), age(-1), max_age(-1), size(0),
208  range(false), freshness_lifetime(0), response_time(0),
209  corrected_initial_age(0), must_revalidate(false),
210  no_cache(false), readers(0) {
211  INIT(&d_response_lock);
212  INIT(&d_response_write_lock);
213  }
214  CacheEntry(const string &u) :
215  url(u), hash(-1), hits(0), cachename(""), etag(""), lm(-1),
216  expires(-1), date(-1), age(-1), max_age(-1), size(0),
217  range(false), freshness_lifetime(0), response_time(0),
218  corrected_initial_age(0), must_revalidate(false),
219  no_cache(false), readers(0) {
220  INIT(&d_response_lock);
221  INIT(&d_response_write_lock);
222  hash = get_hash(url);
223  }
224  };
225 
226  // Typedefs for CacheTable. A CacheTable is a vector of vectors of
227  // CacheEntries. The outer vector is accessed using the hash value.
228  // Entries with matching hashes occupy successive positions in the inner
229  // vector (that's how hash collisions are resolved). Search the inner
230  // vector for a specific match.
231  typedef vector<CacheEntry *> CacheEntries;
232  typedef CacheEntries::iterator CacheEntriesIter;
233 
234  typedef CacheEntries **CacheTable;// Array of pointers to CacheEntries
235 
236  friend class HTTPCacheTest;
237 
238 private:
239  CacheTable d_cache_table;
240 
241  string d_cache_root;
242  unsigned int d_block_size; // File block size.
243  unsigned long d_current_size;
244 
245  string d_cache_index;
246  int d_new_entries;
247 
248  map<FILE *, HTTPCacheTable::CacheEntry *> d_locked_entries;
249 
250  // Make these private to prevent use
251  HTTPCacheTable(const HTTPCacheTable &) {
252  throw InternalErr(__FILE__, __LINE__, "unimplemented");
253  }
254 
255  HTTPCacheTable &operator=(const HTTPCacheTable &) {
256  throw InternalErr(__FILE__, __LINE__, "unimplemented");
257  }
258 
259  HTTPCacheTable() {
260  throw InternalErr(__FILE__, __LINE__, "unimplemented");
261  }
262 
263  CacheTable &get_cache_table() { return d_cache_table; }
264  CacheEntry *get_locked_entry_from_cache_table(int hash, const string &url); /*const*/
265 
266 public:
267  HTTPCacheTable(const string &cache_root, int block_size);
268  ~HTTPCacheTable();
269 
271  unsigned long get_current_size() const { return d_current_size; }
272  void set_current_size(unsigned long sz) { d_current_size = sz; }
273 
274  unsigned int get_block_size() const { return d_block_size; }
275  void set_block_size(unsigned int sz) { d_block_size = sz; }
276 
277  int get_new_entries() const { return d_new_entries; }
278  void increment_new_entries() { ++d_new_entries; }
279 
280  string get_cache_root() { return d_cache_root; }
281  void set_cache_root(const string &cr) { d_cache_root = cr; }
283 
284  void delete_expired_entries(time_t time = 0);
285  void delete_by_hits(int hits);
286  void delete_by_size(unsigned int size);
287  void delete_all_entries();
288 
289  bool cache_index_delete();
290  bool cache_index_read();
291  CacheEntry *cache_index_parse_line(const char *line);
292  void cache_index_write();
293 
294  string create_hash_directory(int hash);
295  void create_location(CacheEntry *entry);
296 
297  void add_entry_to_cache_table(CacheEntry *entry);
298  void remove_cache_entry(HTTPCacheTable::CacheEntry *entry);
299 
300  void remove_entry_from_cache_table(const string &url);
301  CacheEntry *get_locked_entry_from_cache_table(const string &url);
302  CacheEntry *get_write_locked_entry_from_cache_table(const string &url);
303 
304  void calculate_time(HTTPCacheTable::CacheEntry *entry,
305  int default_expiration, time_t request_time);
306  void parse_headers(HTTPCacheTable::CacheEntry *entry,
307  unsigned long max_entry_size, const vector<string> &headers);
308 
309  // These should move back to HTTPCache
310  void bind_entry_to_data(CacheEntry *entry, FILE *body);
311  void uncouple_entry_from_data(FILE *body);
312  bool is_locked_read_responses();
313 };
314 
315 } // namespace libdap
316 #endif
#define DBGN(x)
Definition: debug.h:59
#define UNLOCK(m)
vector< CacheEntry * > CacheEntries
void set_block_size(unsigned int sz)
CacheEntries::iterator CacheEntriesIter
A class for software fault reporting.
Definition: InternalErr.h:64
#define TRYLOCK(m)
#define DBG(x)
Definition: debug.h:58
void set_current_size(unsigned long sz)
unsigned int get_block_size() const
int get_hash(const string &url)
void set_size(unsigned long sz)
#define LOCK(m)
CacheEntries ** CacheTable
unsigned long get_current_size() const
#define INIT(m)
void set_cache_root(const string &cr)