Merge lp:~tdfischer/zeitgeist/event-caching into lp:~zeitgeist/zeitgeist/bluebird

Proposed by Trever Fischer
Status: Needs review
Proposed branch: lp:~tdfischer/zeitgeist/event-caching
Merge into: lp:~zeitgeist/zeitgeist/bluebird
Diff against target: 313 lines (+198/-5)
7 files modified
.bzrignore (+1/-0)
extensions/fts++/Makefile.am (+1/-0)
src/Makefile.am (+1/-0)
src/db-reader.vala (+27/-5)
src/event-cache.vala (+77/-0)
test/direct/Makefile.am (+7/-0)
test/direct/event-cache-test.vala (+84/-0)
To merge this branch: bzr merge lp:~tdfischer/zeitgeist/event-caching
Reviewer Review Type Date Requested Status
Siegfried Gevatter Needs Fixing
Review via email: mp+97450@code.launchpad.net

Description of the change

Implements a LRU cache for events, to reduce hitting the database on every request.

To post a comment you must log in.
422. By Trever Fischer

Add files I missed

423. By Trever Fischer

Ignore the new test

424. By Trever Fischer

Remove the test binary that was accidentally committed

425. By Trever Fischer

Fix handling of null events, and use a pre-sized GenericArray to reduce CRITICAL messages

Revision history for this message
Siegfried Gevatter (rainct) wrote :

Hi Trever,

Nice work, thanks for working on this!

Some comments:

> max_cache_size = 1024;
We have a (so far unused) constant for this in src/utils.vala: Utils.CACHE_SIZE.

+ uncached_ids.resize(uncached_ids.length+1);
+ uncached_ids[uncached_ids.length-1] = event_ids[i];
You can use "+=" here (which looks nicer and does power-of-two allocations).

+ cache = new EventCache();
                              ^ space
+ for(int i = 0; i < event_ids.length; i++)
     ^ space
And more spaces missing in function declarations in event-cache.vala.

Also, see the comment:

// TODO: Consider if we still want the cache. [...]
// It'd also benchmark it again first, we may have better options
// to enhance the performance of SQLite now, and event processing
// will be faster now being C.

Some numbers about how this affects performance for different queries (cold query vs hot query vs mixed query with and without cache).

review: Needs Fixing
Revision history for this message
Trever Fischer (tdfischer) wrote :

Updated. I'll start working on providing some analysis.

426. By Trever Fischer

style++, and use automatic array power of two allocation

Unmerged revisions

426. By Trever Fischer

style++, and use automatic array power of two allocation

425. By Trever Fischer

Fix handling of null events, and use a pre-sized GenericArray to reduce CRITICAL messages

424. By Trever Fischer

Remove the test binary that was accidentally committed

423. By Trever Fischer

Ignore the new test

422. By Trever Fischer

Add files I missed

421. By Trever Fischer

Implement LRU event cache

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2012-02-14 16:57:23 +0000
3+++ .bzrignore 2012-03-30 14:51:19 +0000
4@@ -68,3 +68,4 @@
5 mimetype-test
6 marshalling-test
7 test/direct/datamodel-test
8+test/direct/event-cache-test
9
10=== modified file 'extensions/fts++/Makefile.am'
11--- extensions/fts++/Makefile.am 2012-02-12 20:17:52 +0000
12+++ extensions/fts++/Makefile.am 2012-03-30 14:51:19 +0000
13@@ -42,6 +42,7 @@
14 ontology-uris.vala \
15 mimetype.vala \
16 ext-dummies.vala \
17+ event-cache.vala \
18 $(NULL)
19
20 libzeitgeist_internal_la_SOURCES = \
21
22=== added symlink 'extensions/fts++/event-cache.vala'
23=== target is u'../../src/event-cache.vala'
24=== modified file 'src/Makefile.am'
25--- src/Makefile.am 2012-02-15 19:55:59 +0000
26+++ src/Makefile.am 2012-03-30 14:51:19 +0000
27@@ -48,6 +48,7 @@
28 ontology.vala \
29 ontology-uris.vala \
30 mimetype.vala \
31+ event-cache.vala \
32 $(NULL)
33
34 zeitgeist_daemon_SOURCES = \
35
36=== modified file 'src/db-reader.vala'
37--- src/db-reader.vala 2012-03-19 19:56:38 +0000
38+++ src/db-reader.vala 2012-03-30 14:51:19 +0000
39@@ -45,6 +45,8 @@
40 protected TableLookup mimetypes_table;
41 protected TableLookup actors_table;
42
43+ protected EventCache cache;
44+
45 public DbReader () throws EngineError
46 {
47 Object (database: new Zeitgeist.SQLite.Database.read_only ());
48@@ -59,6 +61,8 @@
49 manifestations_table = new TableLookup (database, "manifestation");
50 mimetypes_table = new TableLookup (database, "mimetype");
51 actors_table = new TableLookup (database, "actor");
52+
53+ cache = new EventCache ();
54 }
55
56 protected Event get_event_from_row (Sqlite.Statement stmt, uint32 event_id)
57@@ -114,10 +118,26 @@
58 // to enhance the performance of SQLite now, and event processing
59 // will be faster now being C.
60
61+ var results = new GenericArray<Event?> ();
62+ results.length = event_ids.length;
63 if (event_ids.length == 0)
64- return new GenericArray<Event?> ();
65-
66- var sql_event_ids = database.get_sql_string_from_event_ids (event_ids);
67+ return results;
68+
69+ uint32[] uncached_ids = new uint32[0];
70+ for (int i = 0; i < event_ids.length; i++)
71+ {
72+ Event? e = cache.get_event (event_ids[i]);
73+ if (e != null) {
74+ results.set(i, e);
75+ } else {
76+ uncached_ids += event_ids[i];
77+ }
78+ }
79+
80+ if (uncached_ids.length == 0)
81+ return results;
82+
83+ var sql_event_ids = database.get_sql_string_from_event_ids (uncached_ids);
84 string sql = """
85 SELECT * FROM event_view
86 WHERE id IN (%s)
87@@ -149,12 +169,14 @@
88 }
89
90 // Sort events according to the sequence of event_ids
91- var results = new GenericArray<Event?> ();
92 results.length = event_ids.length;
93 int i = 0;
94 foreach (var id in event_ids)
95 {
96- results.set(i++, events.lookup (id));
97+ Event e = events.lookup (id);
98+ if (e != null)
99+ cache.cache_event (e);
100+ results.set(i++, e);
101 }
102
103 return results;
104
105=== added file 'src/event-cache.vala'
106--- src/event-cache.vala 1970-01-01 00:00:00 +0000
107+++ src/event-cache.vala 2012-03-30 14:51:19 +0000
108@@ -0,0 +1,77 @@
109+/* event-cache.vala
110+ *
111+ * Copyright © 2012 Collabora Ltd.
112+ * By Trever Fischer <trever.fischer@collabora.co.uk>
113+ *
114+ * This program is free software: you can redistribute it and/or modify
115+ * it under the terms of the GNU Lesser General Public License as published by
116+ * the Free Software Foundation, either version 2.1 of the License, or
117+ * (at your option) any later version.
118+ *
119+ * This program is distributed in the hope that it will be useful,
120+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
121+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
122+ * GNU General Public License for more details.
123+ *
124+ * You should have received a copy of the GNU Lesser General Public License
125+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
126+ *
127+ */
128+
129+using Zeitgeist;
130+
131+namespace Zeitgeist
132+{
133+public class EventCache : Object
134+{
135+
136+ private HashTable<uint32?, Event> cache_table;
137+ private Queue<uint32> lru_queue;
138+ private uint max_cache_size;
139+
140+ construct
141+ {
142+ cache_table = new HashTable<uint32?, Event> (int_hash, int_equal);
143+ lru_queue = new Queue<uint32>();
144+ max_cache_size = Utils.CACHE_SIZE;
145+ }
146+
147+ public Event? get_event(uint32 id)
148+ {
149+ Event? e = cache_table.get (id);
150+ if (e != null)
151+ {
152+ lru_queue.remove_all (id);
153+ lru_queue.push_tail (id);
154+ }
155+ return e;
156+ }
157+
158+ public void cache_event(Event e)
159+ {
160+ cache_table.set (e.id, e);
161+ lru_queue.remove_all (e.id);
162+ lru_queue.push_tail (e.id);
163+
164+ while (lru_queue.length > max_cache_size)
165+ {
166+ uint32 target = lru_queue.pop_head ();
167+ cache_table.remove (target);
168+ }
169+ }
170+
171+ public uint size
172+ {
173+ get { return lru_queue.length; }
174+ }
175+
176+ public uint max_size
177+ {
178+ get { return max_cache_size; }
179+ set { max_cache_size = value; }
180+ }
181+}
182+
183+}
184+
185+// vim:expandtab:ts=4:sw=4
186
187=== modified file 'test/direct/Makefile.am'
188--- test/direct/Makefile.am 2012-02-15 18:55:42 +0000
189+++ test/direct/Makefile.am 2012-03-30 14:51:19 +0000
190@@ -11,6 +11,7 @@
191
192 TESTS = \
193 datamodel-test \
194+ event-cache-test \
195 marshalling-test \
196 mimetype-test \
197 query-operators-test \
198@@ -36,8 +37,12 @@
199 $(top_srcdir)/src/ontology.vala \
200 $(top_srcdir)/src/ontology-uris.vala \
201 $(top_srcdir)/src/mimetype.vala \
202+ $(top_srcdir)/src/event-cache.vala \
203 $(NULL)
204
205+event-cache-test: event-cache-test.vala $(SRC_FILES)
206+ $(VALA_V)$(VALAC) $(VALAFLAGS) -o $@ $^
207+
208 datamodel-test: datamodel-test.vala $(SRC_FILES)
209 $(VALA_V)$(VALAC) $(VALAFLAGS) -o $@ $^
210
211@@ -66,11 +71,13 @@
212 query-operators-test \
213 table-lookup-test \
214 where-clause-test \
215+ event-cache-test \
216 $(NULL)
217
218 EXTRA_DIST = \
219 assertions.vapi \
220 datamodel-test.vala \
221+ event-cache-test.vala \
222 marshalling-test.vala \
223 mimetype-test.vala \
224 query-operators-test.vala \
225
226=== added file 'test/direct/event-cache-test.vala'
227--- test/direct/event-cache-test.vala 1970-01-01 00:00:00 +0000
228+++ test/direct/event-cache-test.vala 2012-03-30 14:51:19 +0000
229@@ -0,0 +1,84 @@
230+/* event-cache-test.vala
231+ *
232+ * Copyright © 2012 Collabora Ltd.
233+ * By Trever Fischer <trever.fischer@collabora.co.uk>
234+ *
235+ * This program is free software: you can redistribute it and/or modify
236+ * it under the terms of the GNU Lesser General Public License as published by
237+ * the Free Software Foundation, either version 2.1 of the License, or
238+ * (at your option) any later version.
239+ *
240+ * This program is distributed in the hope that it will be useful,
241+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
242+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
243+ * GNU General Public License for more details.
244+ *
245+ * You should have received a copy of the GNU Lesser General Public License
246+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
247+ *
248+ */
249+
250+using Zeitgeist;
251+using Assertions;
252+
253+int main (string[] args)
254+{
255+ Test.init (ref args);
256+ Log.set_always_fatal (LogLevelFlags.LEVEL_CRITICAL);
257+
258+ Test.add_func("/EventCache/basic", basic_test);
259+ Test.add_func("/EventCache/size", size_test);
260+ Test.add_func("/EventCache/expiration", expiration_test);
261+
262+ return Test.run ();
263+}
264+
265+public void basic_test ()
266+{
267+ EventCache c = new EventCache ();
268+ for (int i = 0; i<1024; i++)
269+ {
270+ Event e = new Event();
271+ e.id = i;
272+ c.cache_event (e);
273+ }
274+ assert (c.size == 1024);
275+}
276+
277+public void size_test ()
278+{
279+ EventCache c = new EventCache ();
280+ c.max_size = 5;
281+ for (int i = 0; i<2048; i++)
282+ {
283+ Event e = new Event();
284+ e.id = i;
285+ c.cache_event (e);
286+ }
287+
288+ assert (c.size == 5);
289+}
290+
291+public void expiration_test ()
292+{
293+ EventCache c = new EventCache ();
294+ c.max_size = 5;
295+ for (int i = 0; i < 5; i++)
296+ {
297+ Event e = new Event();
298+ e.id = i;
299+ c.cache_event (e);
300+ }
301+
302+ // Refresh the LRU stamp for #0, so #30 expires #1
303+ c.get_event(0);
304+ Event e = new Event();
305+ e.id = 30;
306+ c.cache_event (e);
307+
308+ assert(c.get_event(0) != null);
309+ assert(c.get_event(1) == null);
310+ assert(c.get_event(30) != null);
311+}
312+
313+// vim:expandtab:ts=4:sw=4

Subscribers

People subscribed via source and target branches