aboutsummaryrefslogtreecommitdiff
path: root/src/psycstore
diff options
context:
space:
mode:
authorGabor X Toth <*@tg-x.net>2013-08-29 15:14:17 +0000
committerGabor X Toth <*@tg-x.net>2013-08-29 15:14:17 +0000
commit81eaa5a9d5ebe1e61790069a2777178abd1b6a2c (patch)
tree2b24561b930dca7ede2d27590e1c434fe19ed365 /src/psycstore
parentb1ed5b9a472bd56796646a70068eb48da0db3e2f (diff)
downloadgnunet-81eaa5a9d5ebe1e61790069a2777178abd1b6a2c.tar.gz
gnunet-81eaa5a9d5ebe1e61790069a2777178abd1b6a2c.zip
psycstore: sqlite plugin
Diffstat (limited to 'src/psycstore')
-rw-r--r--src/psycstore/Makefile.am63
-rw-r--r--src/psycstore/gnunet-service-psycstore.c44
-rw-r--r--src/psycstore/plugin_psycstore_sqlite.c858
-rw-r--r--src/psycstore/psycstore.conf5
-rw-r--r--src/psycstore/psycstore_api.c71
5 files changed, 969 insertions, 72 deletions
diff --git a/src/psycstore/Makefile.am b/src/psycstore/Makefile.am
index 461ec6c4e..48f8d5ff7 100644
--- a/src/psycstore/Makefile.am
+++ b/src/psycstore/Makefile.am
@@ -1,13 +1,6 @@
1INCLUDES = -I$(top_srcdir)/src/include 1INCLUDES = -I$(top_srcdir)/src/include
2 2
3if MINGW 3plugindir = $(libdir)/gnunet
4 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
5endif
6
7if USE_COVERAGE
8 AM_CFLAGS = --coverage -O0
9 XLIB = -lgcov
10endif
11 4
12pkgcfgdir= $(pkgdatadir)/config.d/ 5pkgcfgdir= $(pkgdatadir)/config.d/
13 6
@@ -17,6 +10,22 @@ pkgcfg_DATA = \
17 psycstore.conf 10 psycstore.conf
18 11
19 12
13if MINGW
14 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
15endif
16
17if USE_COVERAGE
18 AM_CFLAGS = --coverage -O0
19 XLIB = -lgcov
20endif
21
22if HAVE_SQLITE
23SQLITE_PLUGIN = libgnunet_plugin_psycstore_sqlite.la
24if HAVE_TESTING
25#SQLITE_TESTS = test_plugin_psycstore_sqlite
26endif
27endif
28
20lib_LTLIBRARIES = libgnunetpsycstore.la 29lib_LTLIBRARIES = libgnunetpsycstore.la
21 30
22libgnunetpsycstore_la_SOURCES = \ 31libgnunetpsycstore_la_SOURCES = \
@@ -29,30 +38,50 @@ libgnunetpsycstore_la_LDFLAGS = \
29 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 38 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
30 -version-info 0:0:0 39 -version-info 0:0:0
31libgnunetpsycstore_la_DEPENDENCIES = \ 40libgnunetpsycstore_la_DEPENDENCIES = \
32 $(top_builddir)/src/util/libgnunetutil.la 41 $(top_builddir)/src/util/libgnunetutil.la
33 42
34bin_PROGRAMS = 43bin_PROGRAMS =
35 44
36libexec_PROGRAMS = \ 45libexec_PROGRAMS = \
37 gnunet-service-psycstore 46 gnunet-service-psycstore
38 47
39gnunet_service_psycstore_SOURCES = \ 48gnunet_service_psycstore_SOURCES = \
40 gnunet-service-psycstore.c 49 gnunet-service-psycstore.c
41gnunet_service_psycstore_LDADD = \ 50gnunet_service_psycstore_LDADD = \
42 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 51 $(top_builddir)/src/statistics/libgnunetstatistics.la \
43 $(top_builddir)/src/util/libgnunetutil.la \ 52 $(top_builddir)/src/util/libgnunetutil.la \
44 $(GN_LIBINTL) 53 $(GN_LIBINTL)
45gnunet_service_psycstore_DEPENDENCIES = \ 54gnunet_service_psycstore_DEPENDENCIES = \
46 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 55 $(top_builddir)/src/statistics/libgnunetstatistics.la \
47 $(top_builddir)/src/util/libgnunetutil.la 56 $(top_builddir)/src/util/libgnunetutil.la
57
58
59plugin_LTLIBRARIES = \
60 $(SQLITE_PLUGIN)
61
62libgnunet_plugin_psycstore_sqlite_la_SOURCES = \
63 plugin_psycstore_sqlite.c
64libgnunet_plugin_psycstore_sqlite_la_LIBADD = \
65 $(top_builddir)/src/psycstore/libgnunetpsycstore.la \
66 $(top_builddir)/src/statistics/libgnunetstatistics.la \
67 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
68 $(LTLIBINTL)
69libgnunet_plugin_psycstore_sqlite_la_LDFLAGS = \
70 $(GN_PLUGIN_LDFLAGS)
71libgnunet_plugin_psycstore_sqlite_la_DEPENDENCIES = \
72 $(top_builddir)/src/statistics/libgnunetstatistics.la \
73 $(top_builddir)/src/util/libgnunetutil.la \
74 libgnunetpsycstore.la
75
48 76
49if HAVE_TESTING 77if HAVE_TESTING
50check_PROGRAMS = \ 78check_PROGRAMS = \
51 test_psycstore 79 test_psycstore \
80 $(SQLITE_TESTS)
52endif 81endif
53 82
54if ENABLE_TEST_RUN 83if ENABLE_TEST_RUN
55TESTS = $(check_PROGRAMS) 84TESTS = $(check_PROGRAMS)
56endif 85endif
57 86
58test_psycstore_SOURCES = \ 87test_psycstore_SOURCES = \
@@ -60,13 +89,13 @@ test_psycstore_SOURCES = \
60test_psycstore_LDADD = \ 89test_psycstore_LDADD = \
61 libgnunetpsycstore.la \ 90 libgnunetpsycstore.la \
62 $(top_builddir)/src/testing/libgnunettesting.la \ 91 $(top_builddir)/src/testing/libgnunettesting.la \
63 $(top_builddir)/src/util/libgnunetutil.la 92 $(top_builddir)/src/util/libgnunetutil.la
64test_psycstore_DEPENDENCIES = \ 93test_psycstore_DEPENDENCIES = \
65 libgnunetpsycstore.la \ 94 libgnunetpsycstore.la \
66 $(top_builddir)/src/testing/libgnunettesting.la \ 95 $(top_builddir)/src/testing/libgnunettesting.la \
67 $(top_builddir)/src/util/libgnunetutil.la 96 $(top_builddir)/src/util/libgnunetutil.la
68 97
69EXTRA_DIST = \ 98EXTRA_DIST = \
70 test_psycstore.conf 99 test_psycstore.conf
71 100
72 101
diff --git a/src/psycstore/gnunet-service-psycstore.c b/src/psycstore/gnunet-service-psycstore.c
index 977f77e06..d8f7a2690 100644
--- a/src/psycstore/gnunet-service-psycstore.c
+++ b/src/psycstore/gnunet-service-psycstore.c
@@ -34,6 +34,7 @@
34#include "gnunet_protocols.h" 34#include "gnunet_protocols.h"
35#include "gnunet_statistics_service.h" 35#include "gnunet_statistics_service.h"
36#include "gnunet_psycstore_service.h" 36#include "gnunet_psycstore_service.h"
37#include "gnunet_psycstore_plugin.h"
37#include "psycstore.h" 38#include "psycstore.h"
38 39
39 40
@@ -53,9 +54,14 @@ static struct GNUNET_STATISTICS_Handle *stats;
53static struct GNUNET_SERVER_NotificationContext *nc; 54static struct GNUNET_SERVER_NotificationContext *nc;
54 55
55/** 56/**
56 * Database file. 57 * Database handle
57 */ 58 */
58static char *db_file; 59static struct GNUNET_PSYCSTORE_PluginFunctions *db;
60
61/**
62 * Name of the database plugin
63 */
64static char *db_lib_name;
59 65
60 66
61/** 67/**
@@ -77,8 +83,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
77 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 83 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
78 stats = NULL; 84 stats = NULL;
79 } 85 }
80 GNUNET_free (db_file); 86 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
81 db_file = NULL; 87 GNUNET_free (db_lib_name);
88 db_lib_name = NULL;
82} 89}
83 90
84 91
@@ -123,7 +130,7 @@ send_result_code (struct GNUNET_SERVER_Client *client,
123 * @param c configuration to use 130 * @param c configuration to use
124 */ 131 */
125static void 132static void
126run (void *cls, 133run (void *cls,
127 struct GNUNET_SERVER_Handle *server, 134 struct GNUNET_SERVER_Handle *server,
128 const struct GNUNET_CONFIGURATION_Handle *c) 135 const struct GNUNET_CONFIGURATION_Handle *c)
129{ 136{
@@ -132,15 +139,30 @@ run (void *cls,
132 }; 139 };
133 140
134 cfg = c; 141 cfg = c;
142
143 /* Loading database plugin */
144 char *database;
135 if (GNUNET_OK != 145 if (GNUNET_OK !=
136 GNUNET_CONFIGURATION_get_value_filename (cfg, "psycstore", 146 GNUNET_CONFIGURATION_get_value_string (cfg, "psycstore", "database",
137 "DB_FILE", 147 &database))
138 &db_file)) 148 {
149 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
150 }
151 else
139 { 152 {
140 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "psycstore", "DB_FILE"); 153 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_psycstore_%s", database);
141 GNUNET_SCHEDULER_shutdown (); 154 db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
155 GNUNET_free (database);
156 }
157 if (NULL == db)
158 {
159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
160 "Could not load database backend `%s'\n",
161 db_lib_name);
162 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
142 return; 163 return;
143 } 164 }
165
144 stats = GNUNET_STATISTICS_create ("psycstore", cfg); 166 stats = GNUNET_STATISTICS_create ("psycstore", cfg);
145 GNUNET_SERVER_add_handlers (server, handlers); 167 GNUNET_SERVER_add_handlers (server, handlers);
146 nc = GNUNET_SERVER_notification_context_create (server, 1); 168 nc = GNUNET_SERVER_notification_context_create (server, 1);
@@ -160,7 +182,7 @@ int
160main (int argc, char *const *argv) 182main (int argc, char *const *argv)
161{ 183{
162 return (GNUNET_OK == 184 return (GNUNET_OK ==
163 GNUNET_SERVICE_run (argc, argv, "psycstore", 185 GNUNET_SERVICE_run (argc, argv, "psycstore",
164 GNUNET_SERVICE_OPTION_NONE, 186 GNUNET_SERVICE_OPTION_NONE,
165 &run, NULL)) ? 0 : 1; 187 &run, NULL)) ? 0 : 1;
166} 188}
diff --git a/src/psycstore/plugin_psycstore_sqlite.c b/src/psycstore/plugin_psycstore_sqlite.c
new file mode 100644
index 000000000..8bec31f12
--- /dev/null
+++ b/src/psycstore/plugin_psycstore_sqlite.c
@@ -0,0 +1,858 @@
1 /*
2 * This file is part of GNUnet
3 * (C) 2009-2013 Christian Grothoff (and other contributing authors)
4 *
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12t * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file psycstore/plugin_psycstore_sqlite.c
23 * @brief sqlite-based psycstore backend
24 * @author Gabor X Toth
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_psycstore_plugin.h"
30#include "gnunet_psycstore_service.h"
31#include "psycstore.h"
32#include <sqlite3.h>
33
34/**
35 * After how many ms "busy" should a DB operation fail for good? A
36 * low value makes sure that we are more responsive to requests
37 * (especially PUTs). A high value guarantees a higher success rate
38 * (SELECTs in iterate can take several seconds despite LIMIT=1).
39 *
40 * The default value of 1s should ensure that users do not experience
41 * huge latencies while at the same time allowing operations to
42 * succeed with reasonable probability.
43 */
44#define BUSY_TIMEOUT_MS 1000
45
46
47/**
48 * Log an error message at log-level 'level' that indicates
49 * a failure of the command 'cmd' on file 'filename'
50 * with the message given by strerror(errno).
51 */
52#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "psycstore-sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
53
54#define LOG(kind,...) GNUNET_log_from (kind, "psycstore-sqlite", __VA_ARGS__)
55
56
57/**
58 * Context for all functions in this plugin.
59 */
60struct Plugin
61{
62
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65 /**
66 * Database filename.
67 */
68 char *fn;
69
70 /**
71 * Native SQLite database handle.
72 */
73 sqlite3 *dbh;
74
75 /**
76 * Precompiled SQL for channel_key_store()
77 */
78 sqlite3_stmt *insert_channel_key;
79
80 /**
81 * Precompiled SQL for slave_key_store()
82 */
83 sqlite3_stmt *insert_slave_key;
84
85
86 /**
87 * Precompiled SQL for membership_store()
88 */
89 sqlite3_stmt *insert_membership;
90
91 /**
92 * Precompiled SQL for membership_test()
93 */
94 sqlite3_stmt *select_membership;
95
96
97 /**
98 * Precompiled SQL for fragment_store()
99 */
100 sqlite3_stmt *insert_fragment;
101
102 /**
103 * Precompiled SQL for fragment_add_flags()
104 */
105 sqlite3_stmt *update_fragment_flags;
106
107 /**
108 * Precompiled SQL for fragment_get()
109 */
110 sqlite3_stmt *select_fragment;
111
112 /**
113 * Precompiled SQL for message_get()
114 */
115 sqlite3_stmt *select_message;
116
117 /**
118 * Precompiled SQL for message_get_fragment()
119 */
120 sqlite3_stmt *select_message_fragment;
121
122 /**
123 * Precompiled SQL for counters_get_master()
124 */
125 sqlite3_stmt *select_master_counters;
126
127 /**
128 * Precompiled SQL for counters_get_slave()
129 */
130 sqlite3_stmt *select_slave_counters;
131
132
133 /**
134 * Precompiled SQL for state_set()
135 */
136 sqlite3_stmt *insert_state_current;
137
138 /**
139 * Precompiled SQL for state_set()
140 */
141 sqlite3_stmt *update_state_current;
142
143 /**
144 * Precompiled SQL for state_set_signed()
145 */
146 sqlite3_stmt *update_state_signed;
147
148 /**
149 * Precompiled SQL for state_sync()
150 */
151 sqlite3_stmt *insert_state_sync;
152
153 /**
154 * Precompiled SQL for state_sync()
155 */
156 sqlite3_stmt *delete_state;
157
158 /**
159 * Precompiled SQL for state_sync()
160 */
161 sqlite3_stmt *insert_state_from_sync;
162
163 /**
164 * Precompiled SQL for state_sync()
165 */
166 sqlite3_stmt *delete_state_sync;
167
168 /**
169 * Precompiled SQL for state_get()
170 */
171 sqlite3_stmt *select_state_one;
172
173 /**
174 * Precompiled SQL for state_get_all()
175 */
176 sqlite3_stmt *select_state_prefix;
177
178};
179
180
181/**
182 * @brief Prepare a SQL statement
183 *
184 * @param dbh handle to the database
185 * @param sql SQL statement, UTF-8 encoded
186 * @param stmt set to the prepared statement
187 * @return 0 on success
188 */
189static int
190sql_prepare (sqlite3 *dbh, const char *sql, sqlite3_stmt **stmt)
191{
192 char *tail;
193 int result;
194
195 result = sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt,
196 (const char **) &tail);
197 LOG (GNUNET_ERROR_TYPE_DEBUG,
198 "Prepared `%s' / %p: %d\n", sql, *stmt, result);
199 if (result != SQLITE_OK)
200 LOG (GNUNET_ERROR_TYPE_ERROR,
201 _("Error preparing SQL query: %s\n %s\n"),
202 sqlite3_errmsg (dbh), sql);
203 return result;
204}
205
206
207/**
208 * @brief Prepare a SQL statement
209 *
210 * @param dbh handle to the database
211 * @param zSql SQL statement, UTF-8 encoded
212 * @param ppStmt set to the prepared statement
213 * @return 0 on success
214 */
215static int
216sql_exec (sqlite3 *dbh, const char *sql)
217{
218 int result;
219
220 result = sqlite3_exec (dbh, sql, NULL, NULL, NULL);
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "Executed `%s' / %d\n", sql, result);
223 if (result != SQLITE_OK)
224 LOG (GNUNET_ERROR_TYPE_ERROR,
225 _("Error executing SQL query: %s\n %s\n"),
226 sqlite3_errmsg (dbh), sql);
227 return result;
228}
229
230
231/**
232 * Initialize the database connections and associated
233 * data structures (create tables and indices
234 * as needed as well).
235 *
236 * @param plugin the plugin context (state for this module)
237 * @return GNUNET_OK on success
238 */
239static int
240database_setup (struct Plugin *plugin)
241{
242 char *filename;
243
244 if (GNUNET_OK !=
245 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "psycstore-sqlite",
246 "FILENAME", &filename))
247 {
248 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
249 "psycstore-sqlite", "FILENAME");
250 return GNUNET_SYSERR;
251 }
252 if (GNUNET_OK != GNUNET_DISK_file_test (filename))
253 {
254 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (filename))
255 {
256 GNUNET_break (0);
257 GNUNET_free (filename);
258 return GNUNET_SYSERR;
259 }
260 }
261 /* filename should be UTF-8-encoded. If it isn't, it's a bug */
262 plugin->fn = filename;
263
264 /* Open database and precompile statements */
265 if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
266 {
267 LOG (GNUNET_ERROR_TYPE_ERROR,
268 _("Unable to initialize SQLite: %s.\n"),
269 sqlite3_errmsg (plugin->dbh));
270 return GNUNET_SYSERR;
271 }
272
273 sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY");
274 sql_exec (plugin->dbh, "PRAGMA synchronous=NORMAL");
275 sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF");
276 sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL");
277 sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"");
278 sql_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE");
279 sql_exec (plugin->dbh, "PRAGMA count_changes=OFF");
280 sql_exec (plugin->dbh, "PRAGMA page_size=4096");
281
282 sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS);
283
284 /* Create tables */
285
286 sql_exec (plugin->dbh,
287 "CREATE TABLE IF NOT EXISTS channels ("
288 " id INTEGER PRIMARY KEY,"
289 " pub_key BLOB UNIQUE"
290 ");");
291
292 sql_exec (plugin->dbh,
293 "CREATE TABLE IF NOT EXISTS slaves ("
294 " id INTEGER PRIMARY KEY,"
295 " pub_key BLOB UNIQUE"
296 ");");
297
298 sql_exec (plugin->dbh,
299 "CREATE TABLE IF NOT EXISTS membership ("
300 " channel_id INTEGER NOT NULL REFERENCES channels(id),"
301 " slave_id INTEGER NOT NULL REFERENCES slaves(id),"
302 " did_join INTEGER NOT NULL,"
303 " announced_at INTEGER NOT NULL,"
304 " effective_since INTEGER NOT NULL,"
305 " group_generation INTEGER NOT NULL"
306 ");");
307 sql_exec (plugin->dbh,
308 "CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
309 "ON membership (channel_id, slave_id);");
310
311 sql_exec (plugin->dbh,
312 "CREATE TABLE IF NOT EXISTS messages ("
313 " channel_id INTEGER NOT NULL,"
314 " hop_counter INTEGER NOT NULL,"
315 " signature BLOB,"
316 " purpose BLOB,"
317 " fragment_id INTEGER NOT NULL,"
318 " fragment_offset INTEGER NOT NULL,"
319 " message_id INTEGER NOT NULL,"
320 " group_generation INTEGER NOT NULL,"
321 " multicast_flags INTEGER NOT NULL,"
322 " psyc_flags INTEGER NOT NULL,"
323 " data BLOB,"
324 " PRIMARY KEY (channel_id, fragment_id),"
325 " UNIQUE (channel_id, message_id, fragment_offset)"
326 ");");
327
328 sql_exec (plugin->dbh,
329 "CREATE TABLE IF NOT EXISTS state ("
330 " channel_id INTEGER NOT NULL,"
331 " name TEXT NOT NULL,"
332 " value_current BLOB, "
333 " value_signed BLOB, "
334 " PRIMARY KEY (channel_id, name)"
335 ");");
336
337 sql_exec (plugin->dbh,
338 "CREATE TABLE IF NOT EXISTS state_sync ("
339 " channel_id INTEGER NOT NULL,"
340 " name TEXT NOT NULL,"
341 " value BLOB, "
342 " PRIMARY KEY (channel_id, name)"
343 ");");
344
345 /* Prepare statements */
346
347 sql_prepare (plugin->dbh,
348 "INSERT OR IGNORE INTO channels (pub_key) VALUES (?);",
349 &plugin->insert_channel_key);
350
351 sql_prepare (plugin->dbh,
352 "INSERT OR IGNORE INTO slaves (pub_key) VALUES (?);",
353 &plugin->insert_slave_key);
354
355 sql_prepare (plugin->dbh,
356 "INSERT INTO membership "
357 " (channel_id, slave_id, did_join, announced_at, "
358 " effective_since, group_generation) "
359 "VALUES ((SELECT id FROM channels WHERE pub_key = ?), "
360 " (SELECT id FROM slaves WHERE pub_key = ?), "
361 " ?, ?, ?, ?);",
362 &plugin->insert_membership);
363
364 sql_prepare (plugin->dbh,
365 "SELECT did_join FROM membership "
366 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
367 " AND slave_id = ? AND effective_since <= ? "
368 "ORDER BY announced_at DESC LIMIT 1;",
369 &plugin->select_membership);
370
371 sql_prepare (plugin->dbh,
372 "INSERT INTO messages "
373 " (channel_id, hop_counter, signature, purpose, "
374 " fragment_id, fragment_offset, message_id, "
375 " group_generation, multicast_flags, psyc_flags, data) "
376 "VALUES ((SELECT id FROM channels WHERE pub_key = ?), "
377 " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
378 &plugin->insert_fragment);
379
380 sql_prepare (plugin->dbh,
381 "UPDATE messages "
382 "SET multicast_flags = multicast_flags | ?, "
383 " psyc_flags = psyc_flags | ? "
384 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
385 " AND message_id = ?;",
386 &plugin->update_fragment_flags);
387
388 sql_prepare (plugin->dbh,
389 "SELECT hop_counter, signature, purpose, "
390 " fragment_offset, message_id, group_generation, "
391 " multicast_flags, psyc_flags, data "
392 "FROM messages "
393 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
394 " AND fragment_id = ?;",
395 &plugin->select_fragment);
396
397 sql_prepare (plugin->dbh,
398 "SELECT hop_counter, signature, purpose, "
399 " fragment_id, fragment_offset, group_generation, "
400 " multicast_flags, psyc_flags, data "
401 "FROM messages "
402 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
403 " AND message_id = ?;",
404 &plugin->select_message);
405
406 sql_prepare (plugin->dbh,
407 "SELECT hop_counter, signature, purpose, "
408 " fragment_id, message_id, group_generation, "
409 " multicast_flags, psyc_flags, data "
410 "FROM messages "
411 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
412 " AND message_id = ? AND fragment_offset = ?;",
413 &plugin->select_message_fragment);
414
415 sql_prepare (plugin->dbh,
416 "SELECT max(fragment_id), max(message_id), max(group_generation) "
417 "FROM messages "
418 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
419 &plugin->select_master_counters);
420
421 sql_prepare (plugin->dbh,
422 "SELECT max(message_id) "
423 "FROM messages "
424 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
425 " AND psyc_flags & ?;",
426 &plugin->select_slave_counters);
427
428 sql_prepare (plugin->dbh,
429 "INSERT OR REPLACE INTO state (channel_id, name, value_current) "
430 "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);",
431 &plugin->insert_state_current);
432
433 sql_prepare (plugin->dbh,
434 "UPDATE state "
435 "SET value_current = ? "
436 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
437 " AND name = ?;",
438 &plugin->update_state_current);
439
440 sql_prepare (plugin->dbh,
441 "UPDATE state "
442 "SET value_signed = value_current "
443 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) ",
444 &plugin->update_state_signed);
445
446 sql_prepare (plugin->dbh,
447 "INSERT INTO state_sync (channel_id, name, value) "
448 "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);",
449 &plugin->insert_state_sync);
450
451 sql_prepare (plugin->dbh,
452 "DELETE FROM state "
453 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
454 &plugin->delete_state);
455
456 sql_prepare (plugin->dbh,
457 "INSERT INTO state "
458 " (channel_id, name, value_current, value_signed) "
459 "SELECT channel_id, name, value, value "
460 "FROM state_sync "
461 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
462 &plugin->insert_state_from_sync);
463
464 sql_prepare (plugin->dbh,
465 "DELETE FROM state_sync "
466 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
467 &plugin->delete_state_sync);
468
469 sql_prepare (plugin->dbh,
470 "SELECT value_current "
471 "FROM state "
472 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?) "
473 " AND name = ?;",
474 &plugin->select_state_one);
475
476 sql_prepare (plugin->dbh,
477 "SELECT value_current "
478 "FROM state "
479 "WHERE name LIKE ? OR name LIKE ?;",
480 &plugin->select_state_prefix);
481
482 return GNUNET_OK;
483}
484
485
486/**
487 * Shutdown database connection and associate data
488 * structures.
489 * @param plugin the plugin context (state for this module)
490 */
491static void
492database_shutdown (struct Plugin *plugin)
493{
494 int result;
495 sqlite3_stmt *stmt;
496
497 if (NULL != plugin->insert_channel_key)
498 sqlite3_finalize (plugin->insert_channel_key);
499
500 if (NULL != plugin->insert_slave_key)
501 sqlite3_finalize (plugin->insert_slave_key);
502
503 if (NULL != plugin->insert_membership)
504 sqlite3_finalize (plugin->insert_membership);
505
506 if (NULL != plugin->select_membership)
507 sqlite3_finalize (plugin->select_membership);
508
509 if (NULL != plugin->insert_fragment)
510 sqlite3_finalize (plugin->insert_fragment);
511
512 if (NULL != plugin->update_fragment_flags)
513 sqlite3_finalize (plugin->update_fragment_flags);
514
515 if (NULL != plugin->select_fragment)
516 sqlite3_finalize (plugin->select_fragment);
517
518 if (NULL != plugin->select_message)
519 sqlite3_finalize (plugin->select_message);
520
521 if (NULL != plugin->select_message_fragment)
522 sqlite3_finalize (plugin->select_message_fragment);
523
524 if (NULL != plugin->select_master_counters)
525 sqlite3_finalize (plugin->select_master_counters);
526
527 if (NULL != plugin->select_slave_counters)
528 sqlite3_finalize (plugin->select_slave_counters);
529
530 if (NULL != plugin->insert_state_current)
531 sqlite3_finalize (plugin->insert_state_current);
532
533 if (NULL != plugin->update_state_current)
534 sqlite3_finalize (plugin->update_state_current);
535
536 if (NULL != plugin->update_state_signed)
537 sqlite3_finalize (plugin->update_state_signed);
538
539 if (NULL != plugin->insert_state_sync)
540 sqlite3_finalize (plugin->insert_state_sync);
541
542 if (NULL != plugin->delete_state)
543 sqlite3_finalize (plugin->delete_state);
544
545 if (NULL != plugin->insert_state_from_sync)
546 sqlite3_finalize (plugin->insert_state_from_sync);
547
548 if (NULL != plugin->delete_state_sync)
549 sqlite3_finalize (plugin->delete_state_sync);
550
551 if (NULL != plugin->select_state_one)
552 sqlite3_finalize (plugin->select_state_one);
553
554 if (NULL != plugin->select_state_prefix)
555 sqlite3_finalize (plugin->select_state_prefix);
556
557 result = sqlite3_close (plugin->dbh);
558 if (result == SQLITE_BUSY)
559 {
560 LOG (GNUNET_ERROR_TYPE_WARNING,
561 _("Tried to close sqlite without finalizing all prepared statements.\n"));
562 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
563 while (stmt != NULL)
564 {
565 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
566 "Closing statement %p\n", stmt);
567 result = sqlite3_finalize (stmt);
568 if (result != SQLITE_OK)
569 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
570 "Failed to close statement %p: %d\n", stmt, result);
571 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
572 }
573 result = sqlite3_close (plugin->dbh);
574 }
575 if (SQLITE_OK != result)
576 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
577
578 GNUNET_free_non_null (plugin->fn);
579}
580
581
582/**
583 * Store join/leave events for a PSYC channel in order to be able to answer
584 * membership test queries later.
585 *
586 * @see GNUNET_PSYCSTORE_membership_store()
587 *
588 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
589 */
590int
591libgnunet_plugin_psycstore_sqlite_membership_store
592 (void *cls,
593 const struct GNUNET_HashCode *channel_key,
594 const struct GNUNET_HashCode *slave_key,
595 int did_join,
596 uint64_t announced_at,
597 uint64_t effective_since,
598 uint64_t group_generation) {
599
600
601}
602
603/**
604 * Test if a member was admitted to the channel at the given message ID.
605 *
606 * @see GNUNET_PSYCSTORE_membership_test()
607 *
608 * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
609 * #GNUNET_SYSERR if there was en error.
610 */
611int
612libgnunet_plugin_psycstore_sqlite_membership_test
613 (void *cls,
614 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
615 const struct GNUNET_CRYPTO_EccPublicKey *slave_key,
616 uint64_t message_id,
617 uint64_t group_generation) {
618
619}
620
621/**
622 * Store a message fragment sent to a channel.
623 *
624 * @see GNUNET_PSYCSTORE_fragment_store()
625 *
626 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
627 */
628int
629libgnunet_plugin_psycstore_sqlite_fragment_store
630 (void *cls,
631 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
632 const struct GNUNET_MULTICAST_MessageHeader *message) {
633
634}
635
636/**
637 * Set additional flags for a given message.
638 *
639 * @param message_id ID of the message.
640 * @param flags Flags to add.
641 *
642 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
643 */
644int
645libgnunet_plugin_psycstore_sqlite_fragment_add_flags
646 (void *cls,
647 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
648 uint64_t message_id,
649 uint64_t multicast_flags,
650 uint64_t psyc_flags) {
651
652}
653
654/**
655 * Retrieve a message fragment by fragment ID.
656 *
657 * @see GNUNET_PSYCSTORE_fragment_get()
658 *
659 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
660 */
661int
662libgnunet_plugin_psycstore_sqlite_fragment_get
663 (void *cls,
664 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
665 uint64_t fragment_id,
666 GNUNET_PSYCSTORE_FragmentCallback cb,
667 void *cb_cls) {
668
669}
670
671/**
672 * Retrieve all fragments of a message.
673 *
674 * @see GNUNET_PSYCSTORE_message_get()
675 *
676 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
677 */
678int
679libgnunet_plugin_psycstore_sqlite_message_get
680 (void *cls,
681 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
682 uint64_t message_id,
683 GNUNET_PSYCSTORE_FragmentCallback cb,
684 void *cb_cls) {
685
686}
687
688/**
689 * Retrieve a fragment of message specified by its message ID and fragment
690 * offset.
691 *
692 * @see GNUNET_PSYCSTORE_message_get_fragment()
693 *
694 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
695 */
696int
697libgnunet_plugin_psycstore_sqlite_message_get_fragment
698 (void *cls,
699 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
700 uint64_t message_id,
701 uint64_t fragment_offset,
702 GNUNET_PSYCSTORE_FragmentCallback cb,
703 void *cb_cls)
704{
705
706}
707
708/**
709 * Retrieve latest values of counters for a channel master.
710 *
711 * @see GNUNET_PSYCSTORE_counters_get_master()
712 *
713 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
714 */
715int
716libgnunet_plugin_psycstore_sqlite_counters_get_master
717 (void *cls,
718 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
719 uint64_t *fragment_id,
720 uint64_t *message_id,
721 uint64_t *group_generation)
722{
723
724}
725
726/**
727 * Retrieve latest values of counters for a channel slave.
728 *
729 * @see GNUNET_PSYCSTORE_counters_get_slave()
730 *
731 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
732 */
733int
734libgnunet_plugin_psycstore_sqlite_counters_get_slave
735 (void *cls,
736 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
737 uint64_t *max_state_msg_id) {
738
739}
740
741/**
742 * Set a state variable to the given value.
743 *
744 * @see GNUNET_PSYCSTORE_state_modify()
745 *
746 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
747 */
748int
749libgnunet_plugin_psycstore_sqlite_state_set
750 (struct GNUNET_PSYCSTORE_Handle *h,
751 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
752 const char *name,
753 size_t value_size,
754 const void *value) {
755
756}
757
758/**
759 * Retrieve a state variable by name.
760 *
761 * @param name Name of the variable to retrieve.
762 * @param[out] value_size Size of value.
763 * @param[out] value Returned value.
764 *
765 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
766 */
767int
768libgnunet_plugin_psycstore_sqlite_state_get
769 (struct GNUNET_PSYCSTORE_Handle *h,
770 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
771 const char *name,
772 GNUNET_PSYCSTORE_StateCallback cb,
773 void *cb_cls) {
774
775}
776
777/**
778 * Retrieve all state variables for a channel with the given prefix.
779 *
780 * @see GNUNET_PSYCSTORE_state_get_all()
781 *
782 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
783 */
784int
785libgnunet_plugin_psycstore_sqlite_state_get_all
786 (struct GNUNET_PSYCSTORE_Handle *h,
787 const struct GNUNET_CRYPTO_EccPublicKey *channel_key,
788 const char *name,
789 GNUNET_PSYCSTORE_StateCallback cb,
790 void *cb_cls) {
791
792}
793
794
795/**
796 * Entry point for the plugin.
797 *
798 * @param cls the "struct GNUNET_PSYCSTORE_PluginEnvironment*"
799 * @return NULL on error, otherwise the plugin context
800 */
801void *
802libgnunet_plugin_psycstore_sqlite_init (void *cls)
803{
804 static struct Plugin plugin;
805 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
806 struct GNUNET_PSYCSTORE_PluginFunctions *api;
807
808 if (NULL != plugin.cfg)
809 return NULL; /* can only initialize once! */
810 memset (&plugin, 0, sizeof (struct Plugin));
811 plugin.cfg = cfg;
812 if (GNUNET_OK != database_setup (&plugin))
813 {
814 database_shutdown (&plugin);
815 return NULL;
816 }
817 api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
818 api->cls = &plugin;
819 api->membership_store = &libgnunet_plugin_psycstore_sqlite_membership_store;
820 api->membership_test = &libgnunet_plugin_psycstore_sqlite_membership_test;
821 api->fragment_store = &libgnunet_plugin_psycstore_sqlite_fragment_store;
822 api->fragment_add_flags = &libgnunet_plugin_psycstore_sqlite_fragment_add_flags;
823 api->fragment_get = &libgnunet_plugin_psycstore_sqlite_fragment_get;
824 api->message_get = &libgnunet_plugin_psycstore_sqlite_message_get;
825 api->message_get_fragment = &libgnunet_plugin_psycstore_sqlite_message_get_fragment;
826 api->counters_get_master = &libgnunet_plugin_psycstore_sqlite_counters_get_master;
827 api->counters_get_slave = &libgnunet_plugin_psycstore_sqlite_counters_get_slave;
828 api->state_set = &libgnunet_plugin_psycstore_sqlite_state_set;
829 api->state_get = &libgnunet_plugin_psycstore_sqlite_state_get;
830 api->state_get_all = &libgnunet_plugin_psycstore_sqlite_state_get_all;
831
832 LOG (GNUNET_ERROR_TYPE_INFO,
833 _("Sqlite database running\n"));
834 return api;
835}
836
837
838/**
839 * Exit point from the plugin.
840 *
841 * @param cls the plugin context (as returned by "init")
842 * @return always NULL
843 */
844void *
845libgnunet_plugin_psycstore_sqlite_done (void *cls)
846{
847 struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
848 struct Plugin *plugin = api->cls;
849
850 database_shutdown (plugin);
851 plugin->cfg = NULL;
852 GNUNET_free (api);
853 LOG (GNUNET_ERROR_TYPE_DEBUG,
854 "sqlite plugin is finished\n");
855 return NULL;
856}
857
858/* end of plugin_psycstore_sqlite.c */
diff --git a/src/psycstore/psycstore.conf b/src/psycstore/psycstore.conf
index 7bfe6e126..5b8dfee68 100644
--- a/src/psycstore/psycstore.conf
+++ b/src/psycstore/psycstore.conf
@@ -5,6 +5,7 @@ BINARY = gnunet-service-psycstore
5UNIXPATH = /tmp/gnunet-service-psycstore.unix 5UNIXPATH = /tmp/gnunet-service-psycstore.unix
6UNIX_MATCH_UID = NO 6UNIX_MATCH_UID = NO
7UNIX_MATCH_GID = YES 7UNIX_MATCH_GID = YES
8DATABASE = sqlite
8 9
9# Path to the SQLite database 10[psycstore-sqlite]
10DB_FILE = $SERVICEHOME/psycstore.sqlite 11FILENAME = $SERVICEHOME/psycstore/sqlite.db
diff --git a/src/psycstore/psycstore_api.c b/src/psycstore/psycstore_api.c
index b31b96c3b..d8d5134b6 100644
--- a/src/psycstore/psycstore_api.c
+++ b/src/psycstore/psycstore_api.c
@@ -340,22 +340,8 @@ reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
340 GNUNET_assert (NULL == h->client); 340 GNUNET_assert (NULL == h->client);
341 h->client = GNUNET_CLIENT_connect ("psycstore", h->cfg); 341 h->client = GNUNET_CLIENT_connect ("psycstore", h->cfg);
342 GNUNET_assert (NULL != h->client); 342 GNUNET_assert (NULL != h->client);
343/*
344 struct GNUNET_PSYCSTORE_OperationHandle *op;
345 struct GNUNET_MessageHeader msg;
346 op = GNUNET_malloc (sizeof (struct GNUNET_PSYCSTORE_OperationHandle) +
347 sizeof (struct GNUNET_MessageHeader));
348 op->h = h;
349 op->msg = (const struct GNUNET_MessageHeader *) &op[1];
350 msg.size = htons (sizeof (msg));
351 msg.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_START);
352 memcpy (&op[1], &msg, sizeof (msg));
353 GNUNET_CONTAINER_DLL_insert (h->op_head,
354 h->op_tail,
355 op);
356 transmit_next (h); 343 transmit_next (h);
357 GNUNET_assert (NULL != h->th); 344 GNUNET_assert (NULL != h->th);
358*/
359} 345}
360 346
361 347
@@ -379,6 +365,35 @@ GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
379 365
380 366
381/** 367/**
368 * Disconnect from PSYCstore service
369 *
370 * @param h handle to destroy
371 */
372void
373GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h)
374{
375 GNUNET_assert (NULL != h);
376 GNUNET_assert (h->op_head == h->op_tail);
377 if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
378 {
379 GNUNET_SCHEDULER_cancel (h->reconnect_task);
380 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
381 }
382 if (NULL != h->th)
383 {
384 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
385 h->th = NULL;
386 }
387 if (NULL != h->client)
388 {
389 GNUNET_CLIENT_disconnect (h->client);
390 h->client = NULL;
391 }
392 GNUNET_free (h);
393}
394
395
396/**
382 * Cancel a PSYCstore operation. Note that the operation MAY still 397 * Cancel a PSYCstore operation. Note that the operation MAY still
383 * be executed; this merely cancels the continuation; if the request 398 * be executed; this merely cancels the continuation; if the request
384 * was already transmitted, the service may still choose to complete 399 * was already transmitted, the service may still choose to complete
@@ -420,32 +435,4 @@ GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op)
420} 435}
421 436
422 437
423/**
424 * Disconnect from PSYCstore service
425 *
426 * @param h handle to destroy
427 */
428void
429GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h)
430{
431 GNUNET_assert (NULL != h);
432 GNUNET_assert (h->op_head == h->op_tail);
433 if (h->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
434 {
435 GNUNET_SCHEDULER_cancel (h->reconnect_task);
436 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
437 }
438 if (NULL != h->th)
439 {
440 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
441 h->th = NULL;
442 }
443 if (NULL != h->client)
444 {
445 GNUNET_CLIENT_disconnect (h->client);
446 h->client = NULL;
447 }
448 GNUNET_free (h);
449}
450
451/* end of psycstore_api.c */ 438/* end of psycstore_api.c */