diff options
Diffstat (limited to 'src/psycstore/plugin_psycstore_sqlite.c')
-rw-r--r-- | src/psycstore/plugin_psycstore_sqlite.c | 858 |
1 files changed, 858 insertions, 0 deletions
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 | ||
12 | t * 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 | */ | ||
60 | struct 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 | */ | ||
189 | static int | ||
190 | sql_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 | */ | ||
215 | static int | ||
216 | sql_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 | */ | ||
239 | static int | ||
240 | database_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 | */ | ||
491 | static void | ||
492 | database_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 | */ | ||
590 | int | ||
591 | libgnunet_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 | */ | ||
611 | int | ||
612 | libgnunet_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 | */ | ||
628 | int | ||
629 | libgnunet_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 | */ | ||
644 | int | ||
645 | libgnunet_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 | */ | ||
661 | int | ||
662 | libgnunet_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 | */ | ||
678 | int | ||
679 | libgnunet_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 | */ | ||
696 | int | ||
697 | libgnunet_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 | */ | ||
715 | int | ||
716 | libgnunet_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 | */ | ||
733 | int | ||
734 | libgnunet_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 | */ | ||
748 | int | ||
749 | libgnunet_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 | */ | ||
767 | int | ||
768 | libgnunet_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 | */ | ||
784 | int | ||
785 | libgnunet_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 | */ | ||
801 | void * | ||
802 | libgnunet_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 | */ | ||
844 | void * | ||
845 | libgnunet_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 */ | ||