libdap Updated for version 3.20.11
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
82namespace libdap {
83
84int get_hash(const string &url);
85
102public:
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
273private:
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 &);
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
297public:
298 HTTPCacheTable(const string &cache_root, int block_size);
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
352 void add_entry_to_cache_table(CacheEntry *entry);
353 void remove_cache_entry(HTTPCacheTable::CacheEntry *entry);
354
355 void remove_entry_from_cache_table(const string &url);
356 CacheEntry *get_locked_entry_from_cache_table(const string &url);
357 CacheEntry *get_write_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 create_location(CacheEntry *entry)
void calculate_time(HTTPCacheTable::CacheEntry *entry, int default_expiration, time_t request_time)
string create_hash_directory(int hash)
CacheEntry * cache_index_parse_line(const char *line)
void parse_headers(HTTPCacheTable::CacheEntry *entry, unsigned long max_entry_size, const vector< string > &headers)
CacheEntry * get_write_locked_entry_from_cache_table(const string &url)
void remove_cache_entry(HTTPCacheTable::CacheEntry *entry)
void add_entry_to_cache_table(CacheEntry *entry)
void remove_entry_from_cache_table(const string &url)
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
int get_hash(const string &url)