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