r17689 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r17688‎ | r17689 | r17690 >
Date:04:35, 15 November 2006
Author:river
Status:old
Tags:
Comment:
new files
Modified paths:
  • /trunk/willow/src/include/cache.h (added) (history)
  • /trunk/willow/src/willow/cache.cc (added) (history)

Diff [purge]

Index: trunk/willow/src/include/cache.h
@@ -0,0 +1,197 @@
 2+/* @(#) $Id$ */
 3+/* This source code is in the public domain. */
 4+/*
 5+ * Willow: Lightweight HTTP reverse-proxy.
 6+ * cache: HTTP entity caching.
 7+ */
 8+
 9+#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
 10+# pragma ident "@(#)$Id$"
 11+#endif
 12+
 13+#ifndef CACHE_H
 14+#define CACHE_H
 15+
 16+#include <map>
 17+#include <set>
 18+using std::map;
 19+using std::multiset;
 20+
 21+#include "willow.h"
 22+#include "wthread.h"
 23+#include "flowio.h"
 24+#include "whttp_header.h"
 25+#include "format.h"
 26+
 27+struct caching_filter;
 28+struct cached_spigot;
 29+
 30+struct cachedentity {
 31+ ~cachedentity(void);
 32+
 33+ imstring url(void) const {
 34+ return _url;
 35+ }
 36+
 37+ bool complete(void) const {
 38+ return _complete;
 39+ }
 40+
 41+ bool isvoid(void) const {
 42+ return _void;
 43+ }
 44+
 45+ void reused(void) {
 46+ _lastuse = time(0);
 47+ }
 48+
 49+ void set_complete(void) {
 50+ WDEBUG((WLOG_DEBUG, format("set_complete: void=%d") % _void));
 51+ if (_void)
 52+ return;
 53+ _complete = true;
 54+ }
 55+
 56+ void store_status(imstring const &status) {
 57+ _status = status;
 58+ }
 59+
 60+ void store_headers(header_list const &h) {
 61+ _headers = h;
 62+ _builthdrs = _headers.build();
 63+ _builtsz = _headers.length();
 64+ }
 65+
 66+private:
 67+ friend struct httpcache;
 68+ friend struct caching_filter;
 69+ friend struct cached_spigot;
 70+
 71+ void ref(void) {
 72+ ++_refs;
 73+ }
 74+
 75+ void deref(void) {
 76+ assert(_refs);
 77+ if (--_refs == 0)
 78+ delete this;
 79+ }
 80+
 81+ cachedentity(imstring const &url, size_t hint = 0);
 82+ void _append(char const *data, size_t size);
 83+
 84+ imstring _url;
 85+ imstring _status;
 86+ vector<char> _data;
 87+ atomic<int> _refs;
 88+ atomic<bool> _complete;
 89+ header_list _headers;
 90+ char *_builthdrs;
 91+ int _builtsz;
 92+ bool _void;
 93+ time_t _lastuse;
 94+};
 95+
 96+struct httpcache {
 97+ httpcache();
 98+ ~httpcache();
 99+
 100+ cachedentity *find_cached(imstring const &url, bool create, bool& wasnew);
 101+ void release(cachedentity *);
 102+ bool purge(imstring const &url);
 103+
 104+private:
 105+ friend struct cachedentity;
 106+ friend struct caching_filter;
 107+
 108+ typedef map<imstring, cachedentity *> entmap;
 109+ struct lru_comparator {
 110+ bool operator() (entmap::iterator a,
 111+ entmap::iterator b) const {
 112+ return a->second->_lastuse < b->second->_lastuse;
 113+ }
 114+ };
 115+
 116+ typedef multiset<entmap::iterator, lru_comparator> lruset;
 117+
 118+ void _remove(cachedentity *ent);
 119+
 120+ entmap _entities;
 121+ lruset _lru;
 122+ lockable _lock, _memlock;
 123+ size_t _cache_mem;
 124+
 125+ void cache_mem_reduce(size_t);
 126+ bool cache_mem_increase(size_t);
 127+};
 128+
 129+struct caching_filter : io::sink, io::spigot {
 130+ caching_filter(cachedentity *ent)
 131+ : _entity(ent) {
 132+ }
 133+
 134+ void sp_cork (void) {
 135+ _sink_spigot->sp_cork();
 136+ }
 137+
 138+ void sp_uncork (void) {
 139+ _sink_spigot->sp_uncork();
 140+ }
 141+
 142+ io::sink_result data_ready (char const *buf, size_t s, ssize_t &d) {
 143+ ssize_t old = d;
 144+ io::sink_result ret;
 145+ ret = _sp_sink->data_ready(buf, s, d);
 146+ _entity->_append(buf, d - old);
 147+ return ret;
 148+ }
 149+
 150+ io::sink_result data_empty (void) {
 151+ _entity->set_complete();
 152+ return _sp_sink->data_empty();
 153+ }
 154+
 155+private:
 156+ cachedentity *_entity;
 157+};
 158+
 159+struct cached_spigot : io::buffering_spigot {
 160+ cached_spigot(cachedentity *ent)
 161+ : _ent(ent)
 162+ , _done(false)
 163+ , _keepalive(false) {}
 164+
 165+ ~cached_spigot() {
 166+ sp_cork();
 167+ }
 168+
 169+ void keepalive(bool ke) {
 170+ _keepalive = ke;
 171+ }
 172+
 173+ bool bs_get_data(void) {
 174+ if (_done) {
 175+ _sp_completed_callee();
 176+ return false;
 177+ }
 178+
 179+ _done = true;
 180+ _buf.add(_ent->_status.data(), _ent->_status.size(), false);
 181+ _buf.add(_ent->_builthdrs, _ent->_builtsz, false);
 182+ static char const ke_header[] = "Keep-Alive: 300\r\n";
 183+ if (_keepalive)
 184+ _buf.add(ke_header, sizeof(ke_header) - 1, false);
 185+ _buf.add("\r\n", 2, false);
 186+ _buf.add(_ent->_data.data(), _ent->_data.size(), false);
 187+ return true;
 188+ }
 189+
 190+private:
 191+ cachedentity *_ent;
 192+ bool _done;
 193+ bool _keepalive;
 194+};
 195+
 196+extern httpcache entitycache;
 197+
 198+#endif
Property changes on: trunk/willow/src/include/cache.h
___________________________________________________________________
Added: svn:keywords
1199 + Id Revision
Index: trunk/willow/src/willow/cache.cc
@@ -0,0 +1,174 @@
 2+/* @(#) $Id$ */
 3+/* This source code is in the public domain. */
 4+/*
 5+ * Willow: Lightweight HTTP reverse-proxy.
 6+ * cache: HTTP entity caching.
 7+ */
 8+
 9+#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
 10+# pragma ident "@(#)$Id$"
 11+#endif
 12+
 13+#include <utility>
 14+using std::make_pair;
 15+
 16+#include "cache.h"
 17+#include "format.h"
 18+#include "wconfig.h"
 19+
 20+httpcache entitycache;
 21+
 22+httpcache::httpcache(void)
 23+ : _cache_mem(0)
 24+{
 25+}
 26+
 27+httpcache::~httpcache(void)
 28+{
 29+}
 30+
 31+cachedentity *
 32+httpcache::find_cached(imstring const &url, bool create, bool &wasnew)
 33+{
 34+map<imstring, cachedentity *>::iterator it;
 35+cachedentity *ret;
 36+
 37+ if (!config.cache_memory)
 38+ return NULL;
 39+
 40+ HOLDING(_lock);
 41+ it = _entities.find(url);
 42+
 43+ if (it != _entities.end()) {
 44+ ret = it->second;
 45+ /* entity was cached */
 46+ WDEBUG((WLOG_DEBUG, format("[%s] cached, complete=%d") % url % ret->_complete));
 47+ ret->ref();
 48+ wasnew = false;
 49+ _lru.erase(it);
 50+ it->second->reused();
 51+ _lru.insert(it);
 52+ return ret;
 53+ }
 54+
 55+ WDEBUG((WLOG_DEBUG, format("[%s] not cached") % url));
 56+ if (!create)
 57+ return NULL;
 58+
 59+ /* need to create new entity */
 60+ ret = new cachedentity(url);
 61+ wasnew = true;
 62+ _lru.insert(_entities.insert(make_pair(url, ret)).first);
 63+ ret->_refs = 2; /* one for _entities and one for the caller */
 64+ return ret;
 65+}
 66+
 67+void
 68+httpcache::release(cachedentity *ent)
 69+{
 70+ if (ent->isvoid()) {
 71+ /* don't keep void objects around */
 72+ ent->deref();
 73+ }
 74+
 75+ ent->deref();
 76+}
 77+
 78+void
 79+httpcache::_remove(cachedentity *ent)
 80+{
 81+ HOLDING(_lock);
 82+map<imstring, cachedentity *>::iterator it;
 83+ if ((it = _entities.find(ent->url())) != _entities.end()) {
 84+ _lru.erase(it);
 85+ _entities.erase(it);
 86+ }
 87+}
 88+
 89+void
 90+httpcache::cache_mem_reduce(size_t n)
 91+{
 92+ HOLDING(_memlock);
 93+ _cache_mem -= n;
 94+}
 95+
 96+bool
 97+httpcache::cache_mem_increase(size_t n)
 98+{
 99+ for (;;) {
 100+ { HOLDING(_memlock);
 101+ if (_cache_mem + n <= config.cache_memory)
 102+ break;
 103+ }
 104+ cachedentity *ent;
 105+ { HOLDING(_lock);
 106+ lruset::iterator it;
 107+ if ((it = _lru.begin()) == _lru.end())
 108+ return false;
 109+ ent = (*it)->second;
 110+ }
 111+ ent->deref();
 112+ }
 113+
 114+ HOLDING(_memlock);
 115+ _cache_mem += n;
 116+ return true;
 117+}
 118+
 119+bool
 120+httpcache::purge(imstring const &url)
 121+{
 122+map<imstring, cachedentity *>::iterator it;
 123+cachedentity *ent;
 124+ { HOLDING(_lock);
 125+ it = _entities.find(url);
 126+
 127+ if (it == _entities.end()) {
 128+ return false;
 129+ }
 130+ ent = it->second;
 131+ }
 132+
 133+ ent->deref();
 134+
 135+ return true;
 136+}
 137+
 138+cachedentity::cachedentity(imstring const &url, size_t hint)
 139+ : _url(url)
 140+ , _refs(0)
 141+ , _complete(false)
 142+ , _builthdrs(NULL)
 143+ , _builtsz(0)
 144+ , _void(false)
 145+ , _lastuse(time(0))
 146+{
 147+ if (hint)
 148+ _data.reserve(hint);
 149+}
 150+
 151+cachedentity::~cachedentity()
 152+{
 153+ entitycache._remove(this);
 154+ entitycache.cache_mem_reduce(_data.size());
 155+ delete[] _builthdrs;
 156+}
 157+
 158+void
 159+cachedentity::_append(char const *data, size_t size)
 160+{
 161+ if (_void)
 162+ return;
 163+
 164+ if (_data.size() + size > config.max_entity_size) {
 165+ _void = true;
 166+ return;
 167+ }
 168+
 169+ if (!entitycache.cache_mem_increase(size)) {
 170+ WDEBUG((WLOG_DEBUG, "object is too large, voiding cache"));
 171+ _void = true;
 172+ return;
 173+ }
 174+ _data.insert(_data.end(), data, data + size);
 175+}
Property changes on: trunk/willow/src/willow/cache.cc
___________________________________________________________________
Added: svn:keywords
1176 + Id Revision