Skip to content

Commit f6e2122

Browse files
author
Sebastiano Merlino
committed
Added response cache implementation facilities
1 parent 45748e9 commit f6e2122

File tree

4 files changed

+173
-8
lines changed

4 files changed

+173
-8
lines changed

src/http_response.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ using namespace std;
2929
namespace httpserver
3030
{
3131

32+
cache_response::~cache_response()
33+
{
34+
ws->unlock_cache_element(content);
35+
}
36+
3237
const std::vector<std::pair<std::string, std::string> > http_response::get_headers()
3338
{
3439
std::vector<std::pair<std::string, std::string> > to_ret;
@@ -99,6 +104,11 @@ void http_file_response::get_raw_response(MHD_Response** response, bool* found,
99104
*found = false;
100105
}
101106

107+
void cache_response::get_raw_response(MHD_Response** response, bool* found, webserver* ws)
108+
{
109+
ws->get_from_cache(content, 0x0, true)->get_raw_response(response, found, ws);
110+
}
111+
102112
void long_polling_receive_response::get_raw_response(MHD_Response** response, bool* found, webserver* ws)
103113
{
104114
#ifdef USE_COMET
@@ -166,6 +176,9 @@ void clone_response(const http_response& hr, http_response** dhrs)
166176
case(http_response::LONG_POLLING_SEND):
167177
*dhrs = new long_polling_send_response(hr);
168178
return;
179+
case(http_response::CACHED_CONTENT):
180+
*dhrs = new cache_response(hr);
181+
return;
169182
}
170183
}
171184

src/httpserver/http_response.hpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ class http_response
6161
BASIC_AUTH_FAIL,
6262
SWITCH_PROTOCOL,
6363
LONG_POLLING_RECEIVE,
64-
LONG_POLLING_SEND
64+
LONG_POLLING_SEND,
65+
CACHED_CONTENT
6566
};
6667

6768
/**
@@ -320,6 +321,7 @@ class http_response
320321

321322
friend class webserver;
322323
friend void clone_response(const http_response& hr, http_response** dhr);
324+
friend class cache_response;
323325
};
324326

325327
class http_string_response : public http_response
@@ -453,9 +455,8 @@ class long_polling_receive_response : public http_response
453455
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
454456
private:
455457
static ssize_t data_generator (void* cls, uint64_t pos, char* buf, size_t max);
456-
457458
int connection_id;
458-
webserver* ws;
459+
httpserver::webserver* ws;
459460
};
460461

461462
class long_polling_send_response : public http_response
@@ -475,6 +476,26 @@ class long_polling_send_response : public http_response
475476
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
476477
};
477478

479+
class cache_response : public http_response
480+
{
481+
public:
482+
cache_response
483+
(
484+
const std::string& key
485+
) : http_response(http_response::CACHED_CONTENT, key)
486+
{
487+
}
488+
489+
cache_response(const http_response& b) : http_response(b) { }
490+
491+
~cache_response();
492+
493+
protected:
494+
virtual void get_raw_response(MHD_Response** res, bool* found, webserver* ws = 0x0);
495+
private:
496+
webserver* ws;
497+
};
498+
478499
void clone_response(http_response* hr, http_response** dhr);
479500

480501
};

src/httpserver/webserver.hpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class long_polling_send_response;
5959
namespace details
6060
{
6161
class http_endpoint;
62+
struct cache_entry;
6263
}
6364

6465
using namespace http;
@@ -136,6 +137,19 @@ class unescaper
136137
virtual void unescape(char* s) const;
137138
};
138139

140+
/*
141+
class cache_object
142+
{
143+
public:
144+
enum mode_T { WRITE, READ };
145+
~cache_object();
146+
private:
147+
cache_entry* elem;
148+
mode_T mode;
149+
cache_object(const modeT& mode);
150+
};
151+
*/
152+
139153
class create_webserver;
140154

141155
/**
@@ -240,15 +254,18 @@ class webserver
240254

241255
void send_message_to_topic(const std::string& topic, const std::string& message);
242256
void send_message_to_consumer(int connection_id, const std::string& message, bool to_lock = true);
243-
244257
void register_to_topics(const std::vector<std::string>& topics, int connection_id, int keepalive_secs = -1, std::string keepalive_msg = "");
245-
246258
size_t read_message(int connection_id, std::string& message);
247-
248259
size_t get_topic_consumers(const std::string& topic, std::set<int>& consumers);
249-
250260
bool pop_signaled(int consumer);
251261

262+
http_response* get_from_cache(const std::string& key, bool* valid, bool lock = false, bool write = false);
263+
void lock_cache_element(const std::string& key, bool write = false);
264+
void unlock_cache_element(const std::string& key);
265+
void put_in_cache(const std::string& key, http_response* value, int validity = -1);
266+
void remove_from_cache(const std::string& key);
267+
void clean_cache();
268+
252269
const logging_delegate* get_logging_delegate() const;
253270

254271
void set_logging_delegate(logging_delegate* log_delegate, bool delete_old = false);
@@ -309,6 +326,9 @@ class webserver
309326
http_resource* internal_error_resource;
310327

311328
std::map<details::http_endpoint, http_resource* > registered_resources;
329+
330+
std::map<std::string, details::cache_entry> response_cache;
331+
pthread_rwlock_t cache_guard;
312332
#ifdef USE_CPP_ZEROX
313333
std::unordered_set<ip_representation> bans;
314334
std::unordered_set<ip_representation> allowances;

src/webserver.cpp

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,29 @@
5151

5252
using namespace std;
5353

54-
namespace httpserver {
54+
namespace httpserver
55+
{
56+
57+
namespace details
58+
{
59+
60+
struct cache_entry
61+
{
62+
long ts;
63+
int validity;
64+
http_response* response;
65+
pthread_rwlock_t elem_guard;
66+
67+
cache_entry(http_response* response, long ts = -1, int validity = -1):
68+
ts(ts),
69+
validity(validity),
70+
response(response)
71+
{
72+
pthread_rwlock_init(&elem_guard, NULL);
73+
}
74+
};
75+
76+
}
5577

5678
using namespace http;
5779

@@ -271,6 +293,7 @@ void webserver::init(http_resource* single_resource)
271293
pthread_mutex_init(&mutexwait, NULL);
272294
pthread_mutex_init(&runguard, NULL);
273295
pthread_cond_init(&mutexcond, NULL);
296+
pthread_rwlock_init(&cache_guard, NULL);
274297
#ifdef USE_COMET
275298
pthread_rwlock_init(&comet_guard, NULL);
276299
pthread_mutex_init(&cleanmux, NULL);
@@ -1308,4 +1331,92 @@ bool webserver::pop_signaled(int consumer)
13081331
#endif //USE_COMET
13091332
}
13101333

1334+
http_response* webserver::get_from_cache(const std::string& key, bool* valid, bool lock, bool write)
1335+
{
1336+
pthread_rwlock_rdlock(&cache_guard);
1337+
*valid = true;
1338+
map<string, details::cache_entry>::iterator it(response_cache.find(key));
1339+
if(it != response_cache.end())
1340+
{
1341+
if(lock)
1342+
{
1343+
if(write)
1344+
pthread_rwlock_wrlock(&((*it).second.elem_guard));
1345+
else
1346+
pthread_rwlock_rdlock(&((*it).second.elem_guard));
1347+
}
1348+
if((*it).second.validity != -1)
1349+
{
1350+
timeval now;
1351+
gettimeofday(&now, NULL);
1352+
if( now.tv_sec - (*it).second.ts > (*it).second.validity)
1353+
*valid = false;
1354+
}
1355+
pthread_rwlock_unlock(&cache_guard);
1356+
return (*it).second.response;
1357+
}
1358+
else
1359+
{
1360+
pthread_rwlock_unlock(&cache_guard);
1361+
return 0x0;
1362+
}
1363+
}
1364+
1365+
void webserver::lock_cache_element(const std::string& key, bool write)
1366+
{
1367+
pthread_rwlock_rdlock(&cache_guard);
1368+
map<string, details::cache_entry>::iterator it(response_cache.find(key));
1369+
if(it != response_cache.end())
1370+
{
1371+
if(write)
1372+
pthread_rwlock_wrlock(&((*it).second.elem_guard));
1373+
else
1374+
pthread_rwlock_rdlock(&((*it).second.elem_guard));
1375+
}
1376+
pthread_rwlock_unlock(&cache_guard);
1377+
}
1378+
1379+
void webserver::unlock_cache_element(const std::string& key)
1380+
{
1381+
pthread_rwlock_rdlock(&cache_guard);
1382+
map<string, details::cache_entry>::iterator it(response_cache.find(key));
1383+
if(it != response_cache.end())
1384+
pthread_rwlock_unlock(&((*it).second.elem_guard));
1385+
pthread_rwlock_unlock(&cache_guard);
1386+
}
1387+
1388+
void webserver::put_in_cache(const std::string& key, http_response* value, int validity)
1389+
{
1390+
if(validity == -1)
1391+
{
1392+
pthread_rwlock_wrlock(&cache_guard);
1393+
response_cache.insert(pair<string, details::cache_entry>(key, details::cache_entry(value)));
1394+
pthread_rwlock_unlock(&cache_guard);
1395+
}
1396+
else
1397+
{
1398+
pthread_rwlock_wrlock(&cache_guard);
1399+
timeval now;
1400+
gettimeofday(&now, NULL);
1401+
response_cache.insert(pair<string, details::cache_entry>(key, details::cache_entry(value, now.tv_sec, validity)));
1402+
pthread_rwlock_unlock(&cache_guard);
1403+
}
1404+
}
1405+
1406+
void webserver::remove_from_cache(const std::string& key)
1407+
{
1408+
pthread_rwlock_wrlock(&cache_guard);
1409+
map<string, details::cache_entry>::iterator it(response_cache.find(key));
1410+
if(it != response_cache.end())
1411+
response_cache.erase(it);
1412+
pthread_rwlock_unlock(&cache_guard);
1413+
}
1414+
1415+
void webserver::clean_cache()
1416+
{
1417+
pthread_rwlock_wrlock(&cache_guard);
1418+
response_cache.clear();
1419+
pthread_rwlock_unlock(&cache_guard);
1420+
}
1421+
13111422
};

0 commit comments

Comments
 (0)