summaryrefslogtreecommitdiff
path: root/project2/common/memoryCache.cpp
blob: 7ab271e182f84b509f7282b3d2be14a45b98c5a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <pch.hpp>
#include "logger.h"
#include "cache.h"
#include <boost/foreach.hpp>
#include "options.h"
#include "rowSet.h"
#include "presenter.h"
#include "safeMapFind.h"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>

class MemoryCache : public Cache {
	public:
		typedef std::vector<VariableType> Key;
		class CachedRowSet : public RowSet, public RowSetPresenter {
			public:
				class MemoryCacheRow : public RowState {
					public:
						typedef std::map<Glib::ustring, const VariableType> AttrMap;
						MemoryCacheRow(const Columns * c) :
							columns(c) {
						}
						const Columns & getColumns() const {
							return *columns;
						}
						RowAttribute resolveAttr(const Glib::ustring & attrName) const {
							return boost::bind(&safeMapLookup<AttributeDoesNotExist, AttrMap>, attrs, attrName);
						}
					private:
						friend class CachedRowSet;
						const Columns * columns;
						AttrMap attrs;
				};
				typedef boost::shared_ptr<MemoryCacheRow> MemoryCacheRowPtr;
				typedef std::list<MemoryCacheRowPtr> DataCache;

				CachedRowSet(const std::vector<VariableType> & k) :
					RowSet(NULL),
					key(k),
					createdAt(time(NULL)),
					col(0)
				{
				}

				void execute(const Glib::ustring&, const RowProcessorCallback & rp, ExecContext *) const {
					BOOST_FOREACH(const DataCache::value_type & mcr, dataCache) {
						mcr->process(rp, false);
					}
				}

				void addAttribute(const Glib::ustring & name, const VariableType & value) const {
					cur->attrs.insert(MemoryCacheRow::AttrMap::value_type(name, value));
				}

				void addNamedValue(const Glib::ustring & name, const VariableType & value) const {
					if (cur->fields.size() <= col) {
						cur->fields.resize(col + 1);
						columns.insert(new Column(col, name));
					}
					cur->fields[col++] = value;
				}

				void addNewRow(const Glib::ustring&) const {
					col = 0;
					cur = MemoryCacheRowPtr(new MemoryCacheRow(&columns));
				}

				void finishRow() const {
					dataCache.push_back(cur);
					cur.reset();
				}

				const Key key;
				const time_t createdAt;

			private:
				mutable unsigned int col;
				mutable Columns columns;
				mutable DataCache dataCache;
				mutable MemoryCacheRowPtr cur;

		};
		typedef boost::intrusive_ptr<CachedRowSet> CachedRowSetPtr;
		typedef boost::intrusive_ptr<const CachedRowSet> CachedRowSetCPtr;

		struct IndexByKey { };
		struct IndexByTime { };
		typedef boost::multi_index::multi_index_container<
			CachedRowSetCPtr,
			boost::multi_index::indexed_by<
				boost::multi_index::ordered_unique<
				boost::multi_index::tag<IndexByKey>, BOOST_MULTI_INDEX_MEMBER(CachedRowSet, const Key, key)>,
			boost::multi_index::ordered_non_unique<
				boost::multi_index::tag<IndexByTime>, BOOST_MULTI_INDEX_MEMBER(CachedRowSet, const time_t, createdAt)>
				> > CacheStore;

		MemoryCache(ScriptNodePtr p) :
			Cache(p)
		{
		}

		RowSetCPtr getCachedRowSet(ExecContext * ec, const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const {
			Key key(makeKey(ec, n, f, ps));
			CacheStore::index<IndexByKey>::type::const_iterator i = Store.get<IndexByKey>().find(key);
			if (i == Store.get<IndexByKey>().end()) {
				return NULL;
			}
			if ((*i)->createdAt < (time(NULL) - CacheLife)) {
				Store.erase(i);
				return NULL;
			}
			return *i;
		}

		RowSetPresenterPtr openFor(ExecContext * ec, const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) {
			return (cur = new CachedRowSet(makeKey(ec, n, f, ps)));
		}

		void save(ExecContext *, const Glib::ustring & , const Glib::ustring & , const IHaveParameters * ) {
			if (cur) {
				Store.insert(cur);
				cur.reset();
			}
		}

		void discard(ExecContext *, const Glib::ustring & , const Glib::ustring & , const IHaveParameters * ) {
			cur.reset();
		}

	private:
		Key makeKey(ExecContext * ec, const Glib::ustring & n, const Glib::ustring & f, const IHaveParameters * ps) const {
			Key key;
			key.push_back(n);
			key.push_back(f);
			applyKeys(ec, [&key](const std::string &, const VariableType & v) { key.push_back(v); }, ps);
			return key;
		}

		CachedRowSetPtr cur;

		friend class CustomMemoryCacheLoader;
		static time_t CacheLife;
		static CacheStore Store;
};
time_t MemoryCache::CacheLife;
MemoryCache::CacheStore MemoryCache::Store;

class CustomMemoryCacheLoader : public ElementLoader::For<MemoryCache> {
	public:
		void onPeriodic() {
			typedef MemoryCache::CacheStore::index<MemoryCache::IndexByTime>::type::iterator iter;
			iter x = MemoryCache::Store.get<MemoryCache::IndexByTime>().begin();
			iter y = MemoryCache::Store.get<MemoryCache::IndexByTime>().upper_bound(time(NULL) - MemoryCache::CacheLife);
			MemoryCache::Store.get<MemoryCache::IndexByTime>().erase(x, y);
		}

		INITOPTIONS;
};
DECLARE_CUSTOM_LOADER("memorycache", CustomMemoryCacheLoader);

DECLARE_OPTIONS(CustomMemoryCacheLoader, "Memory Cache options")
("cache.memory.life", Options::value(&MemoryCache::CacheLife, 3600),
 "The age of cache entries after which they are removed (seconds)")
END_OPTIONS(CustomMemoryCacheLoader);