libdap Updated for version 3.21.0
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 <map>
39#include <string>
40#include <vector>
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) \
64 do { \
65 int code = pthread_mutex_lock((m)); \
66 if (code != 0) \
67 throw InternalErr(__FILE__, __LINE__, string("Mutex lock: ") + strerror(code)); \
68 } while (0);
69
70//+ long_to_string(code));
71#define UNLOCK(m) \
72 do { \
73 int code = pthread_mutex_unlock((m)); \
74 if (code != 0) \
75 throw InternalErr(__FILE__, __LINE__, string("Mutex unlock: ") + strerror(code)); \
76 } while (0);
77
78#define TRYLOCK(m) pthread_mutex_trylock((m))
79#define INIT(m) pthread_mutex_init((m), 0)
80#define DESTROY(m) pthread_mutex_destroy((m))
81
82// using namespace std;
83
84namespace libdap {
85
86int get_hash(const string &url);
87
103class HTTPCacheTable {
104public:
116 struct CacheEntry {
117 private:
118 string url; // Location
119 int hash;
120 int hits; // Hit counts
121 string cachename;
122
123 string etag;
124 time_t lm; // Last modified
125 time_t expires;
126 time_t date; // From the response header.
127 time_t age;
128 time_t max_age; // From Cache-Control
129
130 unsigned long size; // Size of cached entity body
131 bool range; // Range is not currently supported. 10/02/02 jhrg
132
133 time_t freshness_lifetime;
134 time_t response_time;
135 time_t corrected_initial_age;
136
137 bool must_revalidate;
138 bool no_cache; // This field is not saved in the index.
139
140 int readers;
141 pthread_mutex_t d_response_lock; // set if being read
142 pthread_mutex_t d_response_write_lock; // set if being written
143
144 // Allow HTTPCacheTable methods access and the test class, too
145 friend class HTTPCacheTable;
146 friend class HTTPCacheTest;
147
148 // Allow access by the functors used in HTTPCacheTable
149 friend class DeleteCacheEntry;
150 friend class WriteOneCacheEntry;
151 friend class DeleteExpired;
152 friend class DeleteByHits;
153 friend class DeleteBySize;
154
155 public:
156 string get_cachename() { return cachename; }
157 string get_etag() { return etag; }
158 time_t get_lm() { return lm; }
159 time_t get_expires() { return expires; }
160 time_t get_max_age() { return max_age; }
161 void set_size(unsigned long sz) { size = sz; }
162 time_t get_freshness_lifetime() { return freshness_lifetime; }
163 time_t get_response_time() { return response_time; }
164 time_t get_corrected_initial_age() { return corrected_initial_age; }
165 bool get_must_revalidate() { return must_revalidate; }
166 void set_no_cache(bool state) { no_cache = state; }
167 bool is_no_cache() { return no_cache; }
168
169 void lock_read_response() {
170 DBG(cerr << "Try locking read response... (" << hex << &d_response_lock << dec << ") ");
171 int status = TRYLOCK(&d_response_lock);
172 if (status != 0 /*&& status == EBUSY*/) {
173 // If locked, wait for any writers
174 LOCK(&d_response_write_lock);
175 UNLOCK(&d_response_write_lock);
176 }
177
178 readers++; // Record number of readers
179
180 DBGN(cerr << "Done" << endl);
181 }
182
183 void unlock_read_response() {
184 readers--;
185 if (readers == 0) {
186 DBG(cerr << "Unlocking read response... (" << hex << &d_response_lock << dec << ") ");
187 UNLOCK(&d_response_lock);
188 DBGN(cerr << "Done" << endl);
189 }
190 }
191
192 void lock_write_response() {
193 DBG(cerr << "locking write response... (" << hex << &d_response_lock << dec << ") ");
194 LOCK(&d_response_lock);
195 LOCK(&d_response_write_lock);
196 DBGN(cerr << "Done" << endl);
197 }
198
199 void unlock_write_response() {
200 DBG(cerr << "Unlocking write response... (" << hex << &d_response_lock << dec << ") ");
201 UNLOCK(&d_response_write_lock);
202 UNLOCK(&d_response_lock);
203 DBGN(cerr << "Done" << endl);
204 }
205
206 CacheEntry()
207 : url(""), hash(-1), hits(0), cachename(""), etag(""), lm(-1), expires(-1), date(-1), age(-1), max_age(-1),
208 size(0), range(false), freshness_lifetime(0), response_time(0), corrected_initial_age(0),
209 must_revalidate(false), no_cache(false), readers(0) {
210 INIT(&d_response_lock);
211 INIT(&d_response_write_lock);
212 }
213 CacheEntry(const string &u)
214 : url(u), hash(-1), hits(0), cachename(""), etag(""), lm(-1), expires(-1), date(-1), age(-1), max_age(-1),
215 size(0), range(false), freshness_lifetime(0), response_time(0), corrected_initial_age(0),
216 must_revalidate(false), no_cache(false), readers(0) {
217 INIT(&d_response_lock);
218 INIT(&d_response_write_lock);
219 hash = get_hash(url);
220 }
221 };
222
223 // Typedefs for CacheTable. A CacheTable is a vector of vectors of
224 // CacheEntries. The outer vector is accessed using the hash value.
225 // Entries with matching hashes occupy successive positions in the inner
226 // vector (that's how hash collisions are resolved). Search the inner
227 // vector for a specific match.
228 typedef vector<CacheEntry *> CacheEntries;
229 typedef CacheEntries::iterator CacheEntriesIter;
230
231 typedef CacheEntries **CacheTable; // Array of pointers to CacheEntries
232
233 friend class HTTPCacheTest;
234
235private:
236 CacheTable d_cache_table;
237
238 string d_cache_root;
239 unsigned int d_block_size; // File block size.
240 unsigned long d_current_size;
241
242 string d_cache_index;
243 int d_new_entries;
244
245 map<FILE *, HTTPCacheTable::CacheEntry *> d_locked_entries;
246
247 // Make these private to prevent use
248 HTTPCacheTable(const HTTPCacheTable &);
249 HTTPCacheTable &operator=(const HTTPCacheTable &);
250 HTTPCacheTable();
251
252 CacheTable &get_cache_table() { return d_cache_table; }
253
254 CacheEntry *get_locked_entry_from_cache_table(int hash, const string &url); /*const*/
255
256public:
257 HTTPCacheTable(const string &cache_root, int block_size);
259
261 unsigned long get_current_size() const { return d_current_size; }
262 void set_current_size(unsigned long sz) { d_current_size = sz; }
263
264 unsigned int get_block_size() const { return d_block_size; }
265 void set_block_size(unsigned int sz) { d_block_size = sz; }
266
267 int get_new_entries() const { return d_new_entries; }
268 void increment_new_entries() { ++d_new_entries; }
269
270 string get_cache_root() { return d_cache_root; }
271 void set_cache_root(const string &cr) { d_cache_root = cr; }
273
274 void delete_expired_entries(time_t time = 0);
275 void delete_by_hits(int hits);
276 void delete_by_size(unsigned int size);
277 void delete_all_entries();
278
279 bool cache_index_delete();
280 bool cache_index_read();
281 CacheEntry *cache_index_parse_line(const char *line);
282 void cache_index_write();
283
284 string create_hash_directory(int hash);
285 void create_location(CacheEntry *entry);
286
288 void remove_cache_entry(HTTPCacheTable::CacheEntry *entry);
289
290 void remove_entry_from_cache_table(const string &url);
291 CacheEntry *get_locked_entry_from_cache_table(const string &url);
293
294 void calculate_time(HTTPCacheTable::CacheEntry *entry, int default_expiration, time_t request_time);
295 void parse_headers(HTTPCacheTable::CacheEntry *entry, unsigned long max_entry_size, const vector<string> &headers);
296
297 // These should move back to HTTPCache
298 void bind_entry_to_data(CacheEntry *entry, FILE *body);
299 void uncouple_entry_from_data(FILE *body);
300 bool is_locked_read_responses();
301};
302
303} // namespace libdap
304#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 AISConnect.cc:30
int get_hash(const string &url)