aboutsummaryrefslogtreecommitdiff
path: root/src/datastore/plugin_datastore_sqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/datastore/plugin_datastore_sqlite.c')
-rw-r--r--src/datastore/plugin_datastore_sqlite.c1374
1 files changed, 0 insertions, 1374 deletions
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
deleted file mode 100644
index 3c2d7f2d4..000000000
--- a/src/datastore/plugin_datastore_sqlite.c
+++ /dev/null
@@ -1,1374 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2009, 2011, 2017 GNUnet e.V.
4 *
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License,
8 * or (at your 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 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file datastore/plugin_datastore_sqlite.c
23 * @brief sqlite-based datastore backend
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_datastore_plugin.h"
29#include "gnunet_sq_lib.h"
30#include <sqlite3.h>
31
32
33/**
34 * We allocate items on the stack at times. To prevent a stack
35 * overflow, we impose a limit on the maximum size for the data per
36 * item. 64k should be enough.
37 */
38#define MAX_ITEM_SIZE 65536
39
40/**
41 * After how many ms "busy" should a DB operation fail for good?
42 * A low value makes sure that we are more responsive to requests
43 * (especially PUTs). A high value guarantees a higher success
44 * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
45 *
46 * The default value of 250ms should ensure that users do not experience
47 * huge latencies while at the same time allowing operations to succeed
48 * with reasonable probability.
49 */
50#define BUSY_TIMEOUT_MS 250
51
52
53/**
54 * Log an error message at log-level 'level' that indicates
55 * a failure of the command 'cmd' on file 'filename'
56 * with the message given by strerror(errno).
57 */
58#define LOG_SQLITE(db, level, cmd) \
59 do \
60 { \
61 GNUNET_log_from (level, \
62 "sqlite", \
63 _ ("`%s' failed at %s:%d with error: %s\n"), \
64 cmd, \
65 __FILE__, \
66 __LINE__, \
67 sqlite3_errmsg (db->dbh)); \
68 } while (0)
69
70
71/**
72 * Log an error message at log-level 'level' that indicates
73 * a failure of the command 'cmd' on file 'filename'
74 * with the message given by strerror(errno).
75 */
76#define LOG_SQLITE_MSG(db, msg, level, cmd) \
77 do \
78 { \
79 GNUNET_log_from (level, \
80 "sqlite", \
81 _ ("`%s' failed at %s:%d with error: %s\n"), \
82 cmd, \
83 __FILE__, \
84 __LINE__, \
85 sqlite3_errmsg (db->dbh)); \
86 GNUNET_asprintf (msg, \
87 _ ("`%s' failed at %s:%u with error: %s"), \
88 cmd, \
89 __FILE__, \
90 __LINE__, \
91 sqlite3_errmsg (db->dbh)); \
92 } while (0)
93
94
95/**
96 * Context for all functions in this plugin.
97 */
98struct Plugin
99{
100 /**
101 * Our execution environment.
102 */
103 struct GNUNET_DATASTORE_PluginEnvironment *env;
104
105 /**
106 * Database filename.
107 */
108 char *fn;
109
110 /**
111 * Native SQLite database handle.
112 */
113 sqlite3 *dbh;
114
115 /**
116 * Precompiled SQL for remove_key.
117 */
118 sqlite3_stmt *remove;
119
120 /**
121 * Precompiled SQL for deletion.
122 */
123 sqlite3_stmt *delRow;
124
125 /**
126 * Precompiled SQL for update.
127 */
128 sqlite3_stmt *update;
129
130 /**
131 * Get maximum repl value in database.
132 */
133 sqlite3_stmt *maxRepl;
134
135 /**
136 * Precompiled SQL for replication decrement.
137 */
138 sqlite3_stmt *updRepl;
139
140 /**
141 * Precompiled SQL for replication selection.
142 */
143 sqlite3_stmt *selRepl;
144
145 /**
146 * Precompiled SQL for expiration selection.
147 */
148 sqlite3_stmt *selExpi;
149
150 /**
151 * Precompiled SQL for expiration selection.
152 */
153 sqlite3_stmt *selZeroAnon;
154
155 /**
156 * Precompiled SQL for insertion.
157 */
158 sqlite3_stmt *insertContent;
159
160 /**
161 * Precompiled SQL for selection
162 */
163 sqlite3_stmt *get[8];
164
165 /**
166 * Should the database be dropped on shutdown?
167 */
168 int drop_on_shutdown;
169};
170
171
172/**
173 * @brief Prepare a SQL statement
174 *
175 * @param dbh handle to the database
176 * @param zSql SQL statement, UTF-8 encoded
177 * @param ppStmt set to the prepared statement
178 * @return 0 on success
179 */
180static int
181sq_prepare (sqlite3 *dbh, const char *zSql, sqlite3_stmt **ppStmt)
182{
183 char *dummy;
184 int result;
185
186 result = sqlite3_prepare_v2 (dbh,
187 zSql,
188 strlen (zSql),
189 ppStmt,
190 (const char **) &dummy);
191 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
192 "sqlite",
193 "Prepared `%s' / %p: %d\n",
194 zSql,
195 *ppStmt,
196 result);
197 return result;
198}
199
200
201/**
202 * Create our database indices.
203 *
204 * @param dbh handle to the database
205 */
206static void
207create_indices (sqlite3 *dbh)
208{
209 /* create indices */
210 if (
211 0 !=
212 (SQLITE_OK !=
213 sqlite3_exec (dbh,
214 "CREATE INDEX IF NOT EXISTS idx_hash ON gn091 (hash)",
215 NULL,
216 NULL,
217 NULL))
218 + (SQLITE_OK !=
219 sqlite3_exec (
220 dbh,
221 "CREATE INDEX IF NOT EXISTS idx_anon_type ON gn091 (anonLevel ASC,type)",
222 NULL,
223 NULL,
224 NULL))
225 + (SQLITE_OK !=
226 sqlite3_exec (dbh,
227 "CREATE INDEX IF NOT EXISTS idx_expire ON gn091 (expire ASC)",
228 NULL,
229 NULL,
230 NULL))
231 + (SQLITE_OK !=
232 sqlite3_exec (
233 dbh,
234 "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn091 (repl,rvalue)",
235 NULL,
236 NULL,
237 NULL)))
238 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
239 "sqlite",
240 "Failed to create indices: %s\n",
241 sqlite3_errmsg (dbh));
242}
243
244
245#if 0
246#define CHECK(a) GNUNET_break (a)
247#define ENULL NULL
248#else
249#define ENULL &e
250#define ENULL_DEFINED 1
251#define CHECK(a) \
252 if (! (a)) \
253 { \
254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", e); \
255 sqlite3_free (e); \
256 }
257#endif
258
259
260/**
261 * Initialize the database connections and associated
262 * data structures (create tables and indices
263 * as needed as well).
264 *
265 * @param cfg our configuration
266 * @param plugin the plugin context (state for this module)
267 * @return #GNUNET_OK on success
268 */
269static int
270database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
271 struct Plugin *plugin)
272{
273 sqlite3_stmt *stmt;
274 char *afsdir;
275
276#if ENULL_DEFINED
277 char *e;
278#endif
279
280 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
281 "datastore-sqlite",
282 "FILENAME",
283 &afsdir))
284 {
285 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
286 "datastore-sqlite",
287 "FILENAME");
288 return GNUNET_SYSERR;
289 }
290 if (GNUNET_OK != GNUNET_DISK_file_test (afsdir))
291 {
292 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir))
293 {
294 GNUNET_break (0);
295 GNUNET_free (afsdir);
296 return GNUNET_SYSERR;
297 }
298 /* database is new or got deleted, reset payload to zero! */
299 if (NULL != plugin->env->duc)
300 plugin->env->duc (plugin->env->cls, 0);
301 }
302 /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
303 plugin->fn = afsdir;
304
305 /* Open database and precompile statements */
306 if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh))
307 {
308 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
309 "sqlite",
310 _ ("Unable to initialize SQLite: %s.\n"),
311 sqlite3_errmsg (plugin->dbh));
312 return GNUNET_SYSERR;
313 }
314 CHECK (
315 SQLITE_OK ==
316 sqlite3_exec (plugin->dbh, "PRAGMA temp_store=MEMORY", NULL, NULL, ENULL));
317 CHECK (
318 SQLITE_OK ==
319 sqlite3_exec (plugin->dbh, "PRAGMA synchronous=OFF", NULL, NULL, ENULL));
320 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
321 "PRAGMA legacy_file_format=OFF",
322 NULL,
323 NULL,
324 ENULL));
325 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
326 "PRAGMA auto_vacuum=INCREMENTAL",
327 NULL,
328 NULL,
329 ENULL));
330 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
331 "PRAGMA locking_mode=EXCLUSIVE",
332 NULL,
333 NULL,
334 ENULL));
335 CHECK (
336 SQLITE_OK ==
337 sqlite3_exec (plugin->dbh, "PRAGMA page_size=4096", NULL, NULL, ENULL));
338
339 CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
340
341
342 /* We have to do it here, because otherwise precompiling SQL might fail */
343 CHECK (SQLITE_OK ==
344 sq_prepare (plugin->dbh,
345 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn091'",
346 &stmt));
347
348 /* FIXME: SQLite does not have unsigned integers! This is ok for the type column because
349 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
350 * we do math or inequality tests, so we can't handle the entire range of uint32_t.
351 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
352 */if ((SQLITE_DONE == sqlite3_step (stmt)) &&
353 (SQLITE_OK != sqlite3_exec (plugin->dbh,
354 "CREATE TABLE gn091 ("
355 " repl INT4 NOT NULL DEFAULT 0,"
356 " type INT4 NOT NULL DEFAULT 0,"
357 " prio INT4 NOT NULL DEFAULT 0,"
358 " anonLevel INT4 NOT NULL DEFAULT 0,"
359 " expire INT8 NOT NULL DEFAULT 0,"
360 " rvalue INT8 NOT NULL,"
361 " hash TEXT NOT NULL DEFAULT '',"
362 " vhash TEXT NOT NULL DEFAULT '',"
363 " value BLOB NOT NULL DEFAULT '')",
364 NULL,
365 NULL,
366 NULL)))
367 {
368 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
369 sqlite3_finalize (stmt);
370 return GNUNET_SYSERR;
371 }
372 sqlite3_finalize (stmt);
373 create_indices (plugin->dbh);
374
375#define RESULT_COLUMNS \
376 "repl, type, prio, anonLevel, expire, hash, value, _ROWID_"
377 if (
378 (SQLITE_OK != sq_prepare (plugin->dbh,
379 "UPDATE gn091 "
380 "SET prio = prio + ?, "
381 "repl = repl + ?, "
382 "expire = MAX(expire, ?) "
383 "WHERE hash = ? AND vhash = ?",
384 &plugin->update)) ||
385 (SQLITE_OK != sq_prepare (plugin->dbh,
386 "UPDATE gn091 "
387 "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
388 &plugin->updRepl)) ||
389 (SQLITE_OK != sq_prepare (plugin->dbh,
390 "SELECT " RESULT_COLUMNS " FROM gn091 "
391 "WHERE repl=?2 AND "
392 " (rvalue>=?1 OR "
393 " NOT EXISTS (SELECT 1 FROM gn091 "
394 "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
395 "ORDER BY rvalue ASC LIMIT 1",
396 &plugin->selRepl)) ||
397 (SQLITE_OK != sq_prepare (plugin->dbh,
398 "SELECT MAX(repl) FROM gn091",
399 &plugin->maxRepl)) ||
400 (SQLITE_OK !=
401 sq_prepare (plugin->dbh,
402 "SELECT " RESULT_COLUMNS " FROM gn091 "
403 "WHERE NOT EXISTS (SELECT 1 FROM gn091 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
404 "ORDER BY expire ASC LIMIT 1",
405 &plugin->selExpi)) ||
406 (SQLITE_OK != sq_prepare (plugin->dbh,
407 "SELECT " RESULT_COLUMNS " FROM gn091 "
408 "WHERE _ROWID_ >= ? AND "
409 "anonLevel = 0 AND "
410 "type = ? "
411 "ORDER BY _ROWID_ ASC LIMIT 1",
412 &plugin->selZeroAnon)) ||
413 (SQLITE_OK !=
414 sq_prepare (plugin->dbh,
415 "INSERT INTO gn091 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
416 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
417 &plugin->insertContent)) ||
418 (SQLITE_OK != sq_prepare (plugin->dbh,
419 "SELECT " RESULT_COLUMNS " FROM gn091 "
420 "WHERE _ROWID_ >= ?1 "
421 "ORDER BY _ROWID_ ASC LIMIT 1",
422 &plugin->get[0])) ||
423 (SQLITE_OK != sq_prepare (plugin->dbh,
424 "SELECT " RESULT_COLUMNS " FROM gn091 "
425 "WHERE _ROWID_ >= ?1 AND "
426 "type = ?4 "
427 "ORDER BY _ROWID_ ASC LIMIT 1",
428 &plugin->get[1])) ||
429 (SQLITE_OK != sq_prepare (plugin->dbh,
430 "SELECT " RESULT_COLUMNS " FROM gn091 "
431 "WHERE _ROWID_ >= ?1 AND "
432 "hash = ?3 "
433 "ORDER BY _ROWID_ ASC LIMIT 1",
434 &plugin->get[2])) ||
435 (SQLITE_OK != sq_prepare (plugin->dbh,
436 "SELECT " RESULT_COLUMNS " FROM gn091 "
437 "WHERE _ROWID_ >= ?1 AND "
438 "hash = ?3 AND "
439 "type = ?4 "
440 "ORDER BY _ROWID_ ASC LIMIT 1",
441 &plugin->get[3])) ||
442 (SQLITE_OK != sq_prepare (plugin->dbh,
443 "SELECT " RESULT_COLUMNS " FROM gn091 "
444 "WHERE _ROWID_ >= ?1 AND "
445 "rvalue >= ?2 "
446 "ORDER BY _ROWID_ ASC LIMIT 1",
447 &plugin->get[4])) ||
448 (SQLITE_OK != sq_prepare (plugin->dbh,
449 "SELECT " RESULT_COLUMNS " FROM gn091 "
450 "WHERE _ROWID_ >= ?1 AND "
451 "rvalue >= ?2 AND "
452 "type = ?4 "
453 "ORDER BY _ROWID_ ASC LIMIT 1",
454 &plugin->get[5])) ||
455 (SQLITE_OK != sq_prepare (plugin->dbh,
456 "SELECT " RESULT_COLUMNS " FROM gn091 "
457 "WHERE _ROWID_ >= ?1 AND "
458 "rvalue >= ?2 AND "
459 "hash = ?3 "
460 "ORDER BY _ROWID_ ASC LIMIT 1",
461 &plugin->get[6])) ||
462 (SQLITE_OK != sq_prepare (plugin->dbh,
463 "SELECT " RESULT_COLUMNS " FROM gn091 "
464 "WHERE _ROWID_ >= ?1 AND "
465 "rvalue >= ?2 AND "
466 "hash = ?3 AND "
467 "type = ?4 "
468 "ORDER BY _ROWID_ ASC LIMIT 1",
469 &plugin->get[7])) ||
470 (SQLITE_OK != sq_prepare (plugin->dbh,
471 "DELETE FROM gn091 WHERE _ROWID_ = ?",
472 &plugin->delRow)) ||
473 (SQLITE_OK != sq_prepare (plugin->dbh,
474 "DELETE FROM gn091 "
475 "WHERE hash = ? AND "
476 "value = ? ",
477 &plugin->remove)) ||
478 false)
479 {
480 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling");
481 return GNUNET_SYSERR;
482 }
483 return GNUNET_OK;
484}
485
486
487/**
488 * Shutdown database connection and associate data
489 * structures.
490 *
491 * @param plugin the plugin context (state for this module)
492 */
493static void
494database_shutdown (struct Plugin *plugin)
495{
496 int result;
497
498#if SQLITE_VERSION_NUMBER >= 3007000
499 sqlite3_stmt *stmt;
500#endif
501
502 if (NULL != plugin->remove)
503 sqlite3_finalize (plugin->remove);
504 if (NULL != plugin->delRow)
505 sqlite3_finalize (plugin->delRow);
506 if (NULL != plugin->update)
507 sqlite3_finalize (plugin->update);
508 if (NULL != plugin->updRepl)
509 sqlite3_finalize (plugin->updRepl);
510 if (NULL != plugin->selRepl)
511 sqlite3_finalize (plugin->selRepl);
512 if (NULL != plugin->maxRepl)
513 sqlite3_finalize (plugin->maxRepl);
514 if (NULL != plugin->selExpi)
515 sqlite3_finalize (plugin->selExpi);
516 if (NULL != plugin->selZeroAnon)
517 sqlite3_finalize (plugin->selZeroAnon);
518 if (NULL != plugin->insertContent)
519 sqlite3_finalize (plugin->insertContent);
520 for (int i = 0; i < 8; ++i)
521 if (NULL != plugin->get[i])
522 sqlite3_finalize (plugin->get[i]);
523 result = sqlite3_close (plugin->dbh);
524#if SQLITE_VERSION_NUMBER >= 3007000
525 if (result == SQLITE_BUSY)
526 {
527 GNUNET_log_from (
528 GNUNET_ERROR_TYPE_WARNING,
529 "sqlite",
530 _ (
531 "Tried to close sqlite without finalizing all prepared statements.\n"));
532 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
533 while (NULL != stmt)
534 {
535 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
536 "sqlite",
537 "Closing statement %p\n",
538 stmt);
539 result = sqlite3_finalize (stmt);
540 if (result != SQLITE_OK)
541 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
542 "sqlite",
543 "Failed to close statement %p: %d\n",
544 stmt,
545 result);
546 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
547 }
548 result = sqlite3_close (plugin->dbh);
549 }
550#endif
551 if (SQLITE_OK != result)
552 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
553 GNUNET_free (plugin->fn);
554}
555
556
557/**
558 * Delete the database entry with the given
559 * row identifier.
560 *
561 * @param plugin the plugin context (state for this module)
562 * @param rid the ID of the row to delete
563 */
564static int
565delete_by_rowid (struct Plugin *plugin, uint64_t rid)
566{
567 struct GNUNET_SQ_QueryParam params[] = { GNUNET_SQ_query_param_uint64 (&rid),
568 GNUNET_SQ_query_param_end };
569
570 if (GNUNET_OK != GNUNET_SQ_bind (plugin->delRow, params))
571 return GNUNET_SYSERR;
572 if (SQLITE_DONE != sqlite3_step (plugin->delRow))
573 {
574 LOG_SQLITE (plugin,
575 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
576 "sqlite3_step");
577 GNUNET_SQ_reset (plugin->dbh, plugin->delRow);
578 return GNUNET_SYSERR;
579 }
580 GNUNET_SQ_reset (plugin->dbh, plugin->delRow);
581 return GNUNET_OK;
582}
583
584
585/**
586 * Store an item in the datastore.
587 *
588 * @param cls closure
589 * @param key key for the item
590 * @param absent true if the key was not found in the bloom filter
591 * @param size number of bytes in @a data
592 * @param data content stored
593 * @param type type of the content
594 * @param priority priority of the content
595 * @param anonymity anonymity-level for the content
596 * @param replication replication-level for the content
597 * @param expiration expiration time for the content
598 * @param cont continuation called with success or failure status
599 * @param cont_cls continuation closure
600 */
601static void
602sqlite_plugin_put (void *cls,
603 const struct GNUNET_HashCode *key,
604 bool absent,
605 uint32_t size,
606 const void *data,
607 enum GNUNET_BLOCK_Type type,
608 uint32_t priority,
609 uint32_t anonymity,
610 uint32_t replication,
611 struct GNUNET_TIME_Absolute expiration,
612 PluginPutCont cont,
613 void *cont_cls)
614{
615 struct Plugin *plugin = cls;
616 struct GNUNET_HashCode vhash;
617 char *msg = NULL;
618
619 GNUNET_CRYPTO_hash (data, size, &vhash);
620
621 if (! absent)
622 {
623 struct GNUNET_SQ_QueryParam params[] =
624 { GNUNET_SQ_query_param_uint32 (&priority),
625 GNUNET_SQ_query_param_uint32 (&replication),
626 GNUNET_SQ_query_param_absolute_time (&expiration),
627 GNUNET_SQ_query_param_auto_from_type (key),
628 GNUNET_SQ_query_param_auto_from_type (&vhash),
629 GNUNET_SQ_query_param_end };
630
631 if (GNUNET_OK != GNUNET_SQ_bind (plugin->update, params))
632 {
633 cont (cont_cls, key, size, GNUNET_SYSERR, _ ("sqlite bind failure"));
634 return;
635 }
636 if (SQLITE_DONE != sqlite3_step (plugin->update))
637 {
638 LOG_SQLITE_MSG (plugin,
639 &msg,
640 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
641 "sqlite3_step");
642 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
643 GNUNET_free (msg);
644 return;
645 }
646 int changes = sqlite3_changes (plugin->dbh);
647 GNUNET_SQ_reset (plugin->dbh, plugin->update);
648 if (0 != changes)
649 {
650 cont (cont_cls, key, size, GNUNET_NO, NULL);
651 return;
652 }
653 }
654
655 uint64_t rvalue;
656 uint32_t type32 = (uint32_t) type;
657 struct GNUNET_SQ_QueryParam params[] =
658 { GNUNET_SQ_query_param_uint32 (&replication),
659 GNUNET_SQ_query_param_uint32 (&type32),
660 GNUNET_SQ_query_param_uint32 (&priority),
661 GNUNET_SQ_query_param_uint32 (&anonymity),
662 GNUNET_SQ_query_param_absolute_time (&expiration),
663 GNUNET_SQ_query_param_uint64 (&rvalue),
664 GNUNET_SQ_query_param_auto_from_type (key),
665 GNUNET_SQ_query_param_auto_from_type (&vhash),
666 GNUNET_SQ_query_param_fixed_size (data, size),
667 GNUNET_SQ_query_param_end };
668 int n;
669 int ret;
670 sqlite3_stmt *stmt;
671
672 if (size > MAX_ITEM_SIZE)
673 {
674 cont (cont_cls, key, size, GNUNET_SYSERR, _ ("Data too large"));
675 return;
676 }
677 GNUNET_log_from (
678 GNUNET_ERROR_TYPE_DEBUG,
679 "sqlite",
680 "Storing in database block with type %u/key `%s'/priority %u/expiration in %s (%s).\n",
681 type,
682 GNUNET_h2s (key),
683 priority,
684 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (
685 expiration),
686 GNUNET_YES),
687 GNUNET_STRINGS_absolute_time_to_string (expiration));
688 stmt = plugin->insertContent;
689 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
690 if (GNUNET_OK != GNUNET_SQ_bind (stmt, params))
691 {
692 cont (cont_cls, key, size, GNUNET_SYSERR, NULL);
693 return;
694 }
695 n = sqlite3_step (stmt);
696 switch (n)
697 {
698 case SQLITE_DONE:
699 if (NULL != plugin->env->duc)
700 plugin->env->duc (plugin->env->cls,
701 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
702 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
703 "sqlite",
704 "Stored new entry (%u bytes)\n",
705 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
706 ret = GNUNET_OK;
707 break;
708
709 case SQLITE_BUSY:
710 GNUNET_break (0);
711 LOG_SQLITE_MSG (plugin,
712 &msg,
713 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
714 "sqlite3_step");
715 ret = GNUNET_SYSERR;
716 break;
717
718 default:
719 LOG_SQLITE_MSG (plugin,
720 &msg,
721 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
722 "sqlite3_step");
723 GNUNET_SQ_reset (plugin->dbh, stmt);
724 database_shutdown (plugin);
725 database_setup (plugin->env->cfg, plugin);
726 cont (cont_cls, key, size, GNUNET_SYSERR, msg);
727 GNUNET_free (msg);
728 return;
729 }
730 GNUNET_SQ_reset (plugin->dbh, stmt);
731 cont (cont_cls, key, size, ret, msg);
732 GNUNET_free (msg);
733}
734
735
736/**
737 * Execute statement that gets a row and call the callback
738 * with the result. Resets the statement afterwards.
739 *
740 * @param plugin the plugin
741 * @param stmt the statement
742 * @param proc processor to call
743 * @param proc_cls closure for @a proc
744 */
745static void
746execute_get (struct Plugin *plugin,
747 sqlite3_stmt *stmt,
748 PluginDatumProcessor proc,
749 void *proc_cls)
750{
751 int n;
752 struct GNUNET_TIME_Absolute expiration;
753 uint32_t replication;
754 uint32_t type;
755 uint32_t priority;
756 uint32_t anonymity;
757 uint64_t rowid;
758 void *value;
759 size_t value_size;
760 struct GNUNET_HashCode key;
761 int ret;
762 struct GNUNET_SQ_ResultSpec rs[] =
763 { GNUNET_SQ_result_spec_uint32 (&replication),
764 GNUNET_SQ_result_spec_uint32 (&type),
765 GNUNET_SQ_result_spec_uint32 (&priority),
766 GNUNET_SQ_result_spec_uint32 (&anonymity),
767 GNUNET_SQ_result_spec_absolute_time (&expiration),
768 GNUNET_SQ_result_spec_auto_from_type (&key),
769 GNUNET_SQ_result_spec_variable_size (&value, &value_size),
770 GNUNET_SQ_result_spec_uint64 (&rowid),
771 GNUNET_SQ_result_spec_end };
772
773 n = sqlite3_step (stmt);
774 switch (n)
775 {
776 case SQLITE_ROW:
777 if (GNUNET_OK != GNUNET_SQ_extract_result (stmt, rs))
778 {
779 GNUNET_break (0);
780 break;
781 }
782 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
783 "sqlite",
784 "Found reply in database with expiration %s\n",
785 GNUNET_STRINGS_absolute_time_to_string (expiration));
786 ret = proc (proc_cls,
787 &key,
788 value_size,
789 value,
790 type,
791 priority,
792 anonymity,
793 replication,
794 expiration,
795 rowid);
796 GNUNET_SQ_cleanup_result (rs);
797 GNUNET_SQ_reset (plugin->dbh, stmt);
798 if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
799 (NULL != plugin->env->duc))
800 plugin->env->duc (plugin->env->cls,
801 -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
802 return;
803
804 case SQLITE_DONE:
805 /* database must be empty */
806 break;
807
808 case SQLITE_BUSY:
809 case SQLITE_ERROR:
810 case SQLITE_MISUSE:
811 default:
812 LOG_SQLITE (plugin,
813 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
814 "sqlite3_step");
815 if (SQLITE_OK != sqlite3_reset (stmt))
816 LOG_SQLITE (plugin,
817 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
818 "sqlite3_reset");
819 GNUNET_break (0);
820 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
821 database_shutdown (plugin);
822 database_setup (plugin->env->cfg, plugin);
823 return;
824 }
825 GNUNET_SQ_reset (plugin->dbh, stmt);
826 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
827}
828
829
830/**
831 * Select a subset of the items in the datastore and call
832 * the given processor for the item.
833 *
834 * @param cls our plugin context
835 * @param next_uid return the result with lowest uid >= next_uid
836 * @param type entries of which type should be considered?
837 * Must not be zero (ANY).
838 * @param proc function to call on the matching value;
839 * will be called with NULL if no value matches
840 * @param proc_cls closure for @a proc
841 */
842static void
843sqlite_plugin_get_zero_anonymity (void *cls,
844 uint64_t next_uid,
845 enum GNUNET_BLOCK_Type type,
846 PluginDatumProcessor proc,
847 void *proc_cls)
848{
849 struct Plugin *plugin = cls;
850 uint32_t type32 = type;
851 struct GNUNET_SQ_QueryParam params[] = { GNUNET_SQ_query_param_uint64 (
852 &next_uid),
853 GNUNET_SQ_query_param_uint32 (
854 &type32),
855 GNUNET_SQ_query_param_end };
856
857 GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
858 if (GNUNET_OK != GNUNET_SQ_bind (plugin->selZeroAnon, params))
859 {
860 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
861 return;
862 }
863 execute_get (plugin, plugin->selZeroAnon, proc, proc_cls);
864}
865
866
867/**
868 * Get results for a particular key in the datastore.
869 *
870 * @param cls closure
871 * @param next_uid return the result with lowest uid >= next_uid
872 * @param random if true, return a random result instead of using next_uid
873 * @param key maybe NULL (to match all entries)
874 * @param type entries of which type are relevant?
875 * Use 0 for any type.
876 * @param proc function to call on the matching value;
877 * will be called with NULL if nothing matches
878 * @param proc_cls closure for @a proc
879 */
880static void
881sqlite_plugin_get_key (void *cls,
882 uint64_t next_uid,
883 bool random,
884 const struct GNUNET_HashCode *key,
885 enum GNUNET_BLOCK_Type type,
886 PluginDatumProcessor proc,
887 void *proc_cls)
888{
889 struct Plugin *plugin = cls;
890 uint64_t rvalue;
891 int use_rvalue = random;
892 uint32_t type32 = (uint32_t) type;
893 int use_type = GNUNET_BLOCK_TYPE_ANY != type;
894 int use_key = NULL != key;
895 sqlite3_stmt *stmt = plugin->get[use_rvalue * 4 + use_key * 2 + use_type];
896 struct GNUNET_SQ_QueryParam params[] =
897 { GNUNET_SQ_query_param_uint64 (&next_uid),
898 GNUNET_SQ_query_param_uint64 (&rvalue),
899 GNUNET_SQ_query_param_auto_from_type (key),
900 GNUNET_SQ_query_param_uint32 (&type32),
901 GNUNET_SQ_query_param_end };
902
903 /* SQLite doesn't like it when you try to bind a parameter greater than the
904 * last numbered parameter, but unused parameters in the middle are OK.
905 */
906 if (! use_type)
907 {
908 params[3] = (struct GNUNET_SQ_QueryParam) GNUNET_SQ_query_param_end;
909 if (! use_key)
910 {
911 params[2] = (struct GNUNET_SQ_QueryParam) GNUNET_SQ_query_param_end;
912 if (! use_rvalue)
913 params[1] = (struct GNUNET_SQ_QueryParam) GNUNET_SQ_query_param_end;
914 }
915 }
916 if (random)
917 {
918 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
919 next_uid = 0;
920 }
921 else
922 rvalue = 0;
923
924 if (GNUNET_OK != GNUNET_SQ_bind (stmt, params))
925 {
926 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
927 return;
928 }
929 execute_get (plugin, stmt, proc, proc_cls);
930}
931
932
933/**
934 * Context for #repl_proc() function.
935 */
936struct ReplCtx
937{
938 /**
939 * Function to call for the result (or the NULL).
940 */
941 PluginDatumProcessor proc;
942
943 /**
944 * Closure for @e proc.
945 */
946 void *proc_cls;
947
948 /**
949 * UID to use.
950 */
951 uint64_t uid;
952
953 /**
954 * Yes if UID was set.
955 */
956 int have_uid;
957};
958
959
960/**
961 * Wrapper for the processor for #sqlite_plugin_get_replication().
962 * Decrements the replication counter and calls the original
963 * processor.
964 *
965 * @param cls closure
966 * @param key key for the content
967 * @param size number of bytes in @a data
968 * @param data content stored
969 * @param type type of the content
970 * @param priority priority of the content
971 * @param anonymity anonymity-level for the content
972 * @param replication replication-level for the content
973 * @param expiration expiration time for the content
974 * @param uid unique identifier for the datum;
975 * maybe 0 if no unique identifier is available
976 * @return #GNUNET_OK for normal return,
977 * #GNUNET_NO to delete the item
978 */
979static int
980repl_proc (void *cls,
981 const struct GNUNET_HashCode *key,
982 uint32_t size,
983 const void *data,
984 enum GNUNET_BLOCK_Type type,
985 uint32_t priority,
986 uint32_t anonymity,
987 uint32_t replication,
988 struct GNUNET_TIME_Absolute expiration,
989 uint64_t uid)
990{
991 struct ReplCtx *rc = cls;
992 int ret;
993
994 if (GNUNET_SYSERR == rc->have_uid)
995 rc->have_uid = GNUNET_NO;
996 ret = rc->proc (rc->proc_cls,
997 key,
998 size,
999 data,
1000 type,
1001 priority,
1002 anonymity,
1003 replication,
1004 expiration,
1005 uid);
1006 if (NULL != key)
1007 {
1008 rc->uid = uid;
1009 rc->have_uid = GNUNET_YES;
1010 }
1011 return ret;
1012}
1013
1014
1015/**
1016 * Get a random item for replication. Returns a single random item
1017 * from those with the highest replication counters. The item's
1018 * replication counter is decremented by one IF it was positive before.
1019 * Call @a proc with all values ZERO or NULL if the datastore is empty.
1020 *
1021 * @param cls closure
1022 * @param proc function to call the value (once only).
1023 * @param proc_cls closure for @a proc
1024 */
1025static void
1026sqlite_plugin_get_replication (void *cls,
1027 PluginDatumProcessor proc,
1028 void *proc_cls)
1029{
1030 struct Plugin *plugin = cls;
1031 struct ReplCtx rc;
1032 uint64_t rvalue = 0;
1033 uint32_t repl;
1034 struct GNUNET_SQ_QueryParam params_sel_repl[] =
1035 { GNUNET_SQ_query_param_uint64 (&rvalue),
1036 GNUNET_SQ_query_param_uint32 (&repl),
1037 GNUNET_SQ_query_param_end };
1038 struct GNUNET_SQ_QueryParam params_upd_repl[] =
1039 { GNUNET_SQ_query_param_uint64 (&rc.uid), GNUNET_SQ_query_param_end };
1040
1041 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1042 "datastore-sqlite",
1043 "Getting random block based on replication order.\n");
1044 if (SQLITE_ROW != sqlite3_step (plugin->maxRepl))
1045 {
1046 GNUNET_SQ_reset (plugin->dbh, plugin->maxRepl);
1047 /* DB empty */
1048 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1049 return;
1050 }
1051 repl = sqlite3_column_int (plugin->maxRepl, 0);
1052 GNUNET_SQ_reset (plugin->dbh, plugin->maxRepl);
1053 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
1054 if (GNUNET_OK != GNUNET_SQ_bind (plugin->selRepl, params_sel_repl))
1055 {
1056 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1057 return;
1058 }
1059 rc.have_uid = GNUNET_SYSERR;
1060 rc.proc = proc;
1061 rc.proc_cls = proc_cls;
1062 execute_get (plugin, plugin->selRepl, &repl_proc, &rc);
1063 if (GNUNET_YES == rc.have_uid)
1064 {
1065 if (GNUNET_OK != GNUNET_SQ_bind (plugin->updRepl, params_upd_repl))
1066 {
1067 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1068 return;
1069 }
1070 if (SQLITE_DONE != sqlite3_step (plugin->updRepl))
1071 LOG_SQLITE (plugin,
1072 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1073 "sqlite3_step");
1074 GNUNET_SQ_reset (plugin->dbh, plugin->updRepl);
1075 }
1076 if (GNUNET_SYSERR == rc.have_uid)
1077 {
1078 /* proc was not called at all so far, do it now. */
1079 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1080 }
1081}
1082
1083
1084/**
1085 * Get a random item that has expired or has low priority.
1086 * Call @a proc with all values ZERO or NULL if the datastore is empty.
1087 *
1088 * @param cls closure
1089 * @param proc function to call the value (once only).
1090 * @param proc_cls closure for @a proc
1091 */
1092static void
1093sqlite_plugin_get_expiration (void *cls,
1094 PluginDatumProcessor proc,
1095 void *proc_cls)
1096{
1097 struct Plugin *plugin = cls;
1098 sqlite3_stmt *stmt;
1099 struct GNUNET_TIME_Absolute now = { 0 };
1100 struct GNUNET_SQ_QueryParam params[] = { GNUNET_SQ_query_param_absolute_time (
1101 &now),
1102 GNUNET_SQ_query_param_end };
1103
1104 GNUNET_log_from (
1105 GNUNET_ERROR_TYPE_DEBUG,
1106 "sqlite",
1107 "Getting random block based on expiration and priority order.\n");
1108 now = GNUNET_TIME_absolute_get ();
1109 stmt = plugin->selExpi;
1110 if (GNUNET_OK != GNUNET_SQ_bind (stmt, params))
1111 {
1112 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
1113 return;
1114 }
1115 execute_get (plugin, stmt, proc, proc_cls);
1116}
1117
1118
1119/**
1120 * Get all of the keys in the datastore.
1121 *
1122 * @param cls closure
1123 * @param proc function to call on each key
1124 * @param proc_cls closure for @a proc
1125 */
1126static void
1127sqlite_plugin_get_keys (void *cls, PluginKeyProcessor proc, void *proc_cls)
1128{
1129 struct Plugin *plugin = cls;
1130 struct GNUNET_HashCode key;
1131 struct GNUNET_SQ_ResultSpec results[] =
1132 { GNUNET_SQ_result_spec_auto_from_type (&key), GNUNET_SQ_result_spec_end };
1133 sqlite3_stmt *stmt;
1134 int ret;
1135
1136 GNUNET_assert (NULL != proc);
1137 if (SQLITE_OK != sq_prepare (plugin->dbh, "SELECT hash FROM gn091", &stmt))
1138 {
1139 LOG_SQLITE (plugin,
1140 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1141 "sqlite_prepare");
1142 proc (proc_cls, NULL, 0);
1143 return;
1144 }
1145 while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
1146 {
1147 if (GNUNET_OK == GNUNET_SQ_extract_result (stmt, results))
1148 proc (proc_cls, &key, 1);
1149 else
1150 GNUNET_break (0);
1151 }
1152 if (SQLITE_DONE != ret)
1153 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
1154 sqlite3_finalize (stmt);
1155 proc (proc_cls, NULL, 0);
1156}
1157
1158
1159/**
1160 * Drop database.
1161 *
1162 * @param cls our plugin context
1163 */
1164static void
1165sqlite_plugin_drop (void *cls)
1166{
1167 struct Plugin *plugin = cls;
1168
1169 plugin->drop_on_shutdown = GNUNET_YES;
1170}
1171
1172
1173/**
1174 * Remove a particular key in the datastore.
1175 *
1176 * @param cls closure
1177 * @param key key for the content
1178 * @param size number of bytes in data
1179 * @param data content stored
1180 * @param cont continuation called with success or failure status
1181 * @param cont_cls continuation closure for @a cont
1182 */
1183static void
1184sqlite_plugin_remove_key (void *cls,
1185 const struct GNUNET_HashCode *key,
1186 uint32_t size,
1187 const void *data,
1188 PluginRemoveCont cont,
1189 void *cont_cls)
1190{
1191 struct Plugin *plugin = cls;
1192 struct GNUNET_SQ_QueryParam params[] =
1193 { GNUNET_SQ_query_param_auto_from_type (key),
1194 GNUNET_SQ_query_param_fixed_size (data, size),
1195 GNUNET_SQ_query_param_end };
1196
1197 if (GNUNET_OK != GNUNET_SQ_bind (plugin->remove, params))
1198 {
1199 cont (cont_cls, key, size, GNUNET_SYSERR, "bind failed");
1200 return;
1201 }
1202 if (SQLITE_DONE != sqlite3_step (plugin->remove))
1203 {
1204 LOG_SQLITE (plugin,
1205 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1206 "sqlite3_step");
1207 GNUNET_SQ_reset (plugin->dbh, plugin->remove);
1208 cont (cont_cls, key, size, GNUNET_SYSERR, "sqlite3_step failed");
1209 return;
1210 }
1211 int changes = sqlite3_changes (plugin->dbh);
1212 GNUNET_SQ_reset (plugin->dbh, plugin->remove);
1213 if (0 == changes)
1214 {
1215 cont (cont_cls, key, size, GNUNET_NO, NULL);
1216 return;
1217 }
1218 if (NULL != plugin->env->duc)
1219 plugin->env->duc (plugin->env->cls,
1220 -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
1221 cont (cont_cls, key, size, GNUNET_OK, NULL);
1222}
1223
1224
1225/**
1226 * Get an estimate of how much space the database is
1227 * currently using.
1228 *
1229 * @param cls the `struct Plugin`
1230 * @return the size of the database on disk (estimate)
1231 */
1232static void
1233sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
1234{
1235 struct Plugin *plugin = cls;
1236 sqlite3_stmt *stmt;
1237 uint64_t pages;
1238 uint64_t page_size;
1239
1240#if ENULL_DEFINED
1241 char *e;
1242#endif
1243
1244 if (NULL == estimate)
1245 return;
1246 if (SQLITE_VERSION_NUMBER < 3006000)
1247 {
1248 GNUNET_log_from (
1249 GNUNET_ERROR_TYPE_WARNING,
1250 "datastore-sqlite",
1251 _ ("sqlite version to old to determine size, assuming zero\n"));
1252 *estimate = 0;
1253 return;
1254 }
1255 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL));
1256 CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh,
1257 "PRAGMA auto_vacuum=INCREMENTAL",
1258 NULL,
1259 NULL,
1260 ENULL));
1261 if (SQLITE_OK != sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt))
1262 {
1263 GNUNET_log_from (
1264 GNUNET_ERROR_TYPE_WARNING,
1265 "datastore-sqlite",
1266 _("error preparing statement\n"));
1267 return;
1268 }
1269 if (SQLITE_ROW == sqlite3_step (stmt))
1270 pages = sqlite3_column_int64 (stmt, 0);
1271 else
1272 pages = 0;
1273 sqlite3_finalize (stmt);
1274 if (SQLITE_OK != sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt))
1275 {
1276 GNUNET_log_from (
1277 GNUNET_ERROR_TYPE_WARNING,
1278 "datastore-sqlite",
1279 _("error preparing statement\n"));
1280 return;
1281 }
1282 if (SQLITE_ROW != sqlite3_step (stmt))
1283 {
1284 GNUNET_log_from (
1285 GNUNET_ERROR_TYPE_WARNING,
1286 "datastore-sqlite",
1287 _("error stepping\n"));
1288 return;
1289 }
1290 page_size = sqlite3_column_int64 (stmt, 0);
1291 sqlite3_finalize (stmt);
1292 GNUNET_log (
1293 GNUNET_ERROR_TYPE_INFO,
1294 _ (
1295 "Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1296 (unsigned long long) pages,
1297 (unsigned long long) page_size);
1298 *estimate = pages * page_size;
1299}
1300
1301
1302/**
1303 * Entry point for the plugin.
1304 *
1305 * @param cls the `struct GNUNET_DATASTORE_PluginEnvironment *`
1306 * @return NULL on error, othrewise the plugin context
1307 */
1308void *
1309libgnunet_plugin_datastore_sqlite_init (void *cls)
1310{
1311 static struct Plugin plugin;
1312 struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
1313 struct GNUNET_DATASTORE_PluginFunctions *api;
1314
1315 if (NULL != plugin.env)
1316 return NULL; /* can only initialize once! */
1317 memset (&plugin, 0, sizeof(struct Plugin));
1318 plugin.env = env;
1319 if (GNUNET_OK != database_setup (env->cfg, &plugin))
1320 {
1321 database_shutdown (&plugin);
1322 return NULL;
1323 }
1324 api = GNUNET_new (struct GNUNET_DATASTORE_PluginFunctions);
1325 api->cls = &plugin;
1326 api->estimate_size = &sqlite_plugin_estimate_size;
1327 api->put = &sqlite_plugin_put;
1328 api->get_key = &sqlite_plugin_get_key;
1329 api->get_replication = &sqlite_plugin_get_replication;
1330 api->get_expiration = &sqlite_plugin_get_expiration;
1331 api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
1332 api->get_keys = &sqlite_plugin_get_keys;
1333 api->drop = &sqlite_plugin_drop;
1334 api->remove_key = &sqlite_plugin_remove_key;
1335 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1336 "sqlite",
1337 _ ("Sqlite database running\n"));
1338 return api;
1339}
1340
1341
1342/**
1343 * Exit point from the plugin.
1344 *
1345 * @param cls the plugin context (as returned by "init")
1346 * @return always NULL
1347 */
1348void *
1349libgnunet_plugin_datastore_sqlite_done (void *cls)
1350{
1351 char *fn;
1352 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1353 struct Plugin *plugin = api->cls;
1354
1355 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1356 "sqlite",
1357 "sqlite plugin is done\n");
1358 fn = NULL;
1359 if (plugin->drop_on_shutdown)
1360 fn = GNUNET_strdup (plugin->fn);
1361 database_shutdown (plugin);
1362 plugin->env = NULL;
1363 GNUNET_free (api);
1364 if (NULL != fn)
1365 {
1366 if (0 != unlink (fn))
1367 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
1368 GNUNET_free (fn);
1369 }
1370 return NULL;
1371}
1372
1373
1374/* end of plugin_datastore_sqlite.c */