aboutsummaryrefslogtreecommitdiff
path: root/src/datastore/plugin_datastore_sqlite.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-06-24 13:39:32 +0000
committerChristian Grothoff <christian@grothoff.org>2009-06-24 13:39:32 +0000
commita913b5f73410eb3f0568670046d3ecf3b233744f (patch)
treedcb13bbc2aa2ed6c23832e4c55a0f843c0a68f31 /src/datastore/plugin_datastore_sqlite.c
parentb2b1773aaa6e7c0c61ff7ac5a5766a8a2ea25495 (diff)
downloadgnunet-a913b5f73410eb3f0568670046d3ecf3b233744f.tar.gz
gnunet-a913b5f73410eb3f0568670046d3ecf3b233744f.zip
stuff
Diffstat (limited to 'src/datastore/plugin_datastore_sqlite.c')
-rw-r--r--src/datastore/plugin_datastore_sqlite.c1195
1 files changed, 1156 insertions, 39 deletions
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index 6bee1a0c9..5ae03b9bb 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -25,7 +25,78 @@
25 */ 25 */
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_statistics_service.h"
28#include "plugin_datastore.h" 29#include "plugin_datastore.h"
30#include <sqlite3.h>
31
32#define DEBUG_SQLITE GNUNET_YES
33
34/**
35 * After how many payload-changing operations
36 * do we sync our statistics?
37 */
38#define MAX_STAT_SYNC_LAG 50
39
40#define QUOTA_STAT_NAME gettext_noop ("file-sharing datastore utilization (in bytes)")
41
42
43/**
44 * Die with an error message that indicates
45 * a failure of the command 'cmd' with the message given
46 * by strerror(errno).
47 */
48#define DIE_SQLITE(db, cmd) do { GNUNET_log_from(GNUNET_ERROR_TYPE_ERROR, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); abort(); } while(0)
49
50/**
51 * Log an error message at log-level 'level' that indicates
52 * a failure of the command 'cmd' on file 'filename'
53 * with the message given by strerror(errno).
54 */
55#define LOG_SQLITE(db, msg, level, cmd) do { GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); if (msg != NULL) GNUNET_asprintf(msg, _("`%s' failed with error: %s\n"), cmd, sqlite3_errmsg(db->dbh)); } while(0)
56
57#define SELECT_IT_LOW_PRIORITY_1 \
58 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash > ?) "\
59 "ORDER BY hash ASC LIMIT 1"
60
61#define SELECT_IT_LOW_PRIORITY_2 \
62 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio > ?) "\
63 "ORDER BY prio ASC, hash ASC LIMIT 1"
64
65#define SELECT_IT_NON_ANONYMOUS_1 \
66 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio = ? AND hash < ? AND anonLevel = 0) "\
67 " ORDER BY hash DESC LIMIT 1"
68
69#define SELECT_IT_NON_ANONYMOUS_2 \
70 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (prio < ? AND anonLevel = 0)"\
71 " ORDER BY prio DESC, hash DESC LIMIT 1"
72
73#define SELECT_IT_EXPIRATION_TIME_1 \
74 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire = ? AND hash > ?) "\
75 " ORDER BY hash ASC LIMIT 1"
76
77#define SELECT_IT_EXPIRATION_TIME_2 \
78 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire > ?) "\
79 " ORDER BY expire ASC, hash ASC LIMIT 1"
80
81#define SELECT_IT_MIGRATION_ORDER_1 \
82 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire = ? AND hash < ?) "\
83 " ORDER BY hash DESC LIMIT 1"
84
85#define SELECT_IT_MIGRATION_ORDER_2 \
86 "SELECT size,type,prio,anonLevel,expire,hash,value,_ROWID_ FROM gn080 WHERE (expire < ?) "\
87 " ORDER BY expire DESC, hash DESC LIMIT 1"
88
89/**
90 * After how many ms "busy" should a DB operation fail for good?
91 * A low value makes sure that we are more responsive to requests
92 * (especially PUTs). A high value guarantees a higher success
93 * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
94 *
95 * The default value of 250ms should ensure that users do not experience
96 * huge latencies while at the same time allowing operations to succeed
97 * with reasonable probability.
98 */
99#define BUSY_TIMEOUT_MS 250
29 100
30 101
31/** 102/**
@@ -37,20 +108,401 @@ struct Plugin
37 * Our execution environment. 108 * Our execution environment.
38 */ 109 */
39 struct GNUNET_DATASTORE_PluginEnvironment *env; 110 struct GNUNET_DATASTORE_PluginEnvironment *env;
111
112 /**
113 * Database filename.
114 */
115 char *fn;
116
117 /**
118 * Native SQLite database handle.
119 */
120 sqlite3 *dbh;
121
122 /**
123 * Precompiled SQL for update.
124 */
125 sqlite3_stmt *updPrio;
126
127 /**
128 * Precompiled SQL for insertion.
129 */
130 sqlite3_stmt *insertContent;
131
132 /**
133 * Handle to the statistics service.
134 */
135 struct GNUNET_STATISTICS_Handle *statistics;
136
137 /**
138 * How much data are we currently storing
139 * in the database?
140 */
141 unsigned long long payload;
142
143 /**
144 * Number of updates that were made to the
145 * payload value since we last synchronized
146 * it with the statistics service.
147 */
148 unsigned int lastSync;
149
150 /**
151 * Should the database be dropped on shutdown?
152 */
153 int drop_on_shutdown;
40}; 154};
41 155
42 156
43/** 157/**
158 * @brief Prepare a SQL statement
159 *
160 * @param zSql SQL statement, UTF-8 encoded
161 */
162static int
163sq_prepare (sqlite3 * dbh, const char *zSql,
164 sqlite3_stmt ** ppStmt)
165{
166 char *dummy;
167 return sqlite3_prepare (dbh,
168 zSql,
169 strlen (zSql), ppStmt, (const char **) &dummy);
170}
171
172
173/**
174 * Create our database indices.
175 */
176static void
177create_indices (sqlite3 * dbh)
178{
179 /* create indices */
180 sqlite3_exec (dbh,
181 "CREATE INDEX idx_hash ON gn080 (hash)", NULL, NULL, NULL);
182 sqlite3_exec (dbh,
183 "CREATE INDEX idx_hash_vhash ON gn080 (hash,vhash)", NULL,
184 NULL, NULL);
185 sqlite3_exec (dbh, "CREATE INDEX idx_prio ON gn080 (prio)", NULL, NULL,
186 NULL);
187 sqlite3_exec (dbh, "CREATE INDEX idx_expire ON gn080 (expire)", NULL, NULL,
188 NULL);
189 sqlite3_exec (dbh, "CREATE INDEX idx_comb3 ON gn080 (prio,anonLevel)", NULL,
190 NULL, NULL);
191 sqlite3_exec (dbh, "CREATE INDEX idx_comb4 ON gn080 (prio,hash,anonLevel)",
192 NULL, NULL, NULL);
193 sqlite3_exec (dbh, "CREATE INDEX idx_comb7 ON gn080 (expire,hash)", NULL,
194 NULL, NULL);
195}
196
197
198
199#if 1
200#define CHECK(a) GNUNET_break(a)
201#define ENULL NULL
202#else
203#define ENULL &e
204#define ENULL_DEFINED 1
205#define CHECK(a) if (! a) { GNUNET_log(GNUNET_ERROR_TYPE_ERRROR, "%s\n", e); sqlite3_free(e); }
206#endif
207
208
209
210
211/**
212 * Initialize the database connections and associated
213 * data structures (create tables and indices
214 * as needed as well).
215 *
216 * @return GNUNET_OK on success
217 */
218static int
219database_setup (struct GNUNET_CONFIGURATION_Handle *cfg,
220 struct Plugin *plugin)
221{
222 sqlite3_stmt *stmt;
223 char *dir;
224 char *afsdir;
225#if ENULL_DEFINED
226 char *e;
227#endif
228
229 if (GNUNET_OK !=
230 GNUNET_CONFIGURATION_get_value_filename (cfg,
231 "FS",
232 "DIR",
233 &afsdir))
234 {
235 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
236 "sqlite",
237 _("Option `%s' in section `%s' missing in configuration!\n"),
238 "DIR",
239 "FS");
240 return GNUNET_SYSERR;
241 }
242 GNUNET_asprintf (&dir, "%s/content/gnunet.dat", afsdir);
243 GNUNET_free (afsdir);
244 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (dir))
245 {
246 GNUNET_break (0);
247 GNUNET_free (dir);
248 return GNUNET_SYSERR;
249 }
250 plugin->fn = GNUNET_STRINGS_to_utf8 (dir, strlen (dir),
251#ifdef ENABLE_NLS
252 nl_langinfo (CODESET)
253#else
254 "UTF-8" /* good luck */
255#endif
256 );
257 GNUNET_free (dir);
258
259 /* Open database and precompile statements */
260 if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
261 {
262 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
263 "sqlite",
264 _("Unable to initialize SQLite: %s.\n"),
265 sqlite3_errmsg (plugin->dbh));
266 return GNUNET_SYSERR;
267 }
268 CHECK (SQLITE_OK ==
269 sqlite3_exec (plugin->dbh,
270 "PRAGMA temp_store=MEMORY", NULL, NULL, ENULL));
271 CHECK (SQLITE_OK ==
272 sqlite3_exec (plugin->dbh,
273 "PRAGMA synchronous=OFF", NULL, NULL, ENULL));
274 CHECK (SQLITE_OK ==
275 sqlite3_exec (plugin->dbh,
276 "PRAGMA count_changes=OFF", NULL, NULL, ENULL));
277 CHECK (SQLITE_OK ==
278 sqlite3_exec (plugin->dbh, "PRAGMA page_size=4092", NULL, NULL, ENULL));
279
280 CHECK (SQLITE_OK == sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS));
281
282
283 /* We have to do it here, because otherwise precompiling SQL might fail */
284 CHECK (SQLITE_OK ==
285 sq_prepare (plugin->dbh,
286 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn080'",
287 &stmt));
288 if ( (sqlite3_step (stmt) == SQLITE_DONE) &&
289 (sqlite3_exec (plugin->dbh,
290 "CREATE TABLE gn080 ("
291 " size INTEGER NOT NULL DEFAULT 0,"
292 " type INTEGER NOT NULL DEFAULT 0,"
293 " prio INTEGER NOT NULL DEFAULT 0,"
294 " anonLevel INTEGER NOT NULL DEFAULT 0,"
295 " expire INTEGER NOT NULL DEFAULT 0,"
296 " hash TEXT NOT NULL DEFAULT '',"
297 " vhash TEXT NOT NULL DEFAULT '',"
298 " value BLOB NOT NULL DEFAULT '')", NULL, NULL,
299 NULL) != SQLITE_OK) )
300 {
301 LOG_SQLITE (plugin, NULL,
302 GNUNET_ERROR_TYPE_ERROR,
303 "sqlite3_exec");
304 sqlite3_finalize (stmt);
305 return GNUNET_SYSERR;
306 }
307 sqlite3_finalize (stmt);
308 create_indices (plugin->dbh);
309
310 CHECK (SQLITE_OK ==
311 sq_prepare (plugin->dbh,
312 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn071'",
313 &stmt));
314 if ( (sqlite3_step (stmt) == SQLITE_DONE) &&
315 (sqlite3_exec (plugin->dbh,
316 "CREATE TABLE gn071 ("
317 " key TEXT NOT NULL DEFAULT '',"
318 " value INTEGER NOT NULL DEFAULT 0)", NULL, NULL,
319 NULL) != SQLITE_OK) )
320 {
321 LOG_SQLITE (plugin, NULL,
322 GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
323 sqlite3_finalize (stmt);
324 return GNUNET_SYSERR;
325 }
326 sqlite3_finalize (stmt);
327
328 if ((sq_prepare (plugin->dbh,
329 "UPDATE gn080 SET prio = prio + ?, expire = MAX(expire,?) WHERE "
330 "_ROWID_ = ?",
331 &plugin->updPrio) != SQLITE_OK) ||
332 (sq_prepare (plugin->dbh,
333 "INSERT INTO gn080 (size, type, prio, "
334 "anonLevel, expire, hash, vhash, value) VALUES "
335 "(?, ?, ?, ?, ?, ?, ?, ?)",
336 &plugin->insertContent) != SQLITE_OK))
337 {
338 LOG_SQLITE (plugin, NULL,
339 GNUNET_ERROR_TYPE_ERROR, "precompiling");
340 return GNUNET_SYSERR;
341 }
342 return GNUNET_OK;
343}
344
345
346/**
347 * Synchronize our utilization statistics with the
348 * statistics service.
349 */
350static void
351sync_stats (struct Plugin *plugin)
352{
353 GNUNET_STATISTICS_set (plugin->statistics,
354 QUOTA_STAT_NAME,
355 plugin->payload,
356 GNUNET_YES);
357 plugin->lastSync = 0;
358}
359
360
361/**
362 * Shutdown database connection and associate data
363 * structures.
364 */
365static void
366database_shutdown (struct Plugin *plugin)
367{
368 if (plugin->lastSync > 0)
369 sync_stats (plugin);
370 if (plugin->updPrio != NULL)
371 sqlite3_finalize (plugin->updPrio);
372 if (plugin->insertContent != NULL)
373 sqlite3_finalize (plugin->insertContent);
374 sqlite3_close (plugin->dbh);
375 GNUNET_free_non_null (plugin->fn);
376}
377
378
379/**
44 * Get an estimate of how much space the database is 380 * Get an estimate of how much space the database is
45 * currently using. 381 * currently using.
46 * @return number of bytes used on disk 382 * @return number of bytes used on disk
47 */ 383 */
48static unsigned long long sqlite_plugin_get_size (void *cls) 384static unsigned long long sqlite_plugin_get_size (void *cls)
49{ 385{
50 return 0; 386 struct Plugin *plugin = cls;
387 return plugin->payload;
388}
389
390
391/**
392 * Delete the database entry with the given
393 * row identifier.
394 */
395static int
396delete_by_rowid (struct Plugin* plugin,
397 unsigned long long rid)
398{
399 sqlite3_stmt *stmt;
400
401 if (sq_prepare (plugin->dbh,
402 "DELETE FROM gn080 WHERE _ROWID_ = ?", &stmt) != SQLITE_OK)
403 {
404 LOG_SQLITE (plugin, NULL,
405 GNUNET_ERROR_TYPE_ERROR |
406 GNUNET_ERROR_TYPE_BULK, "sq_prepare");
407 return GNUNET_SYSERR;
408 }
409 sqlite3_bind_int64 (stmt, 1, rid);
410 if (SQLITE_DONE != sqlite3_step (stmt))
411 {
412 LOG_SQLITE (plugin, NULL,
413 GNUNET_ERROR_TYPE_ERROR |
414 GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
415 sqlite3_finalize (stmt);
416 return GNUNET_SYSERR;
417 }
418 sqlite3_finalize (stmt);
419 return GNUNET_OK;
51} 420}
52 421
53 422
423/**
424 * Context for the universal iterator.
425 */
426struct NextContext;
427
428/**
429 * Type of a function that will prepare
430 * the next iteration.
431 *
432 * @param cls closure
433 * @param nc the next context; NULL for the last
434 * call which gives the callback a chance to
435 * clean up the closure
436 * @return GNUNET_OK on success, GNUNET_NO if there are
437 * no more values, GNUNET_SYSERR on error
438 */
439typedef int (*PrepareFunction)(void *cls,
440 struct NextContext *nc);
441
442
443/**
444 * Context we keep for the "next request" callback.
445 */
446struct NextContext
447{
448 /**
449 * Internal state.
450 */
451 struct Plugin *plugin;
452
453 /**
454 * Function to call on the next value.
455 */
456 PluginIterator iter;
457
458 /**
459 * Closure for iter.
460 */
461 void *iter_cls;
462
463 /**
464 * Function to call to prepare the next
465 * iteration.
466 */
467 PrepareFunction prep;
468
469 /**
470 * Closure for prep.
471 */
472 void *prep_cls;
473
474 /**
475 * Statement that the iterator will get the data
476 * from (updated or set by prep).
477 */
478 sqlite3_stmt *stmt;
479
480 /**
481 * Row ID of the last result.
482 */
483 unsigned long long last_rowid;
484
485 /**
486 * Expiration time of the last value visited.
487 */
488 struct GNUNET_TIME_Absolute lastExpiration;
489
490 /**
491 * Priority of the last value visited.
492 */
493 unsigned int lastPriority;
494
495 /**
496 * Number of results processed so far.
497 */
498 unsigned int count;
499
500 /**
501 * Set to GNUNET_YES if we must stop now.
502 */
503 int end_it;
504};
505
54 506
55/** 507/**
56 * Function invoked on behalf of a "PluginIterator" 508 * Function invoked on behalf of a "PluginIterator"
@@ -68,6 +520,107 @@ static void
68sqlite_next_request (void *next_cls, 520sqlite_next_request (void *next_cls,
69 int end_it) 521 int end_it)
70{ 522{
523 static struct GNUNET_TIME_Absolute zero;
524 struct NextContext * nc= next_cls;
525 struct Plugin *plugin = nc->plugin;
526 unsigned long long rowid;
527 sqlite3_stmt *stmtd;
528 int ret;
529 unsigned int type;
530 unsigned int size;
531 unsigned int priority;
532 unsigned int anonymity;
533 struct GNUNET_TIME_Absolute expiration;
534 const GNUNET_HashCode *key;
535 const void *data;
536
537 sqlite3_reset (nc->stmt);
538 if ( (GNUNET_YES == end_it) ||
539 (GNUNET_YES == nc->end_it) ||
540 (GNUNET_OK != (nc->prep(nc->prep_cls,
541 nc))) ||
542 (SQLITE_ROW != sqlite3_step (nc->stmt)) )
543 {
544 END:
545 nc->iter (nc->iter_cls,
546 NULL, NULL, 0, NULL, 0, 0, 0,
547 zero, 0);
548 nc->prep (nc->prep_cls, NULL);
549 GNUNET_free (nc);
550 return;
551 }
552
553 rowid = sqlite3_column_int64 (nc->stmt, 7);
554 nc->last_rowid = rowid;
555 type = sqlite3_column_int (nc->stmt, 1);
556 size = sqlite3_column_bytes (nc->stmt, 6);
557 if (sqlite3_column_bytes (nc->stmt, 5) != sizeof (GNUNET_HashCode))
558 {
559 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
560 "sqlite",
561 _("Invalid data in database. Trying to fix (by deletion).\n"));
562 if (SQLITE_OK != sqlite3_reset (nc->stmt))
563 LOG_SQLITE (nc->plugin, NULL,
564 GNUNET_ERROR_TYPE_ERROR |
565 GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
566 if (sq_prepare
567 (nc->plugin->dbh,
568 "DELETE FROM gn080 WHERE NOT LENGTH(hash) = ?",
569 &stmtd) != SQLITE_OK)
570 {
571 LOG_SQLITE (nc->plugin, NULL,
572 GNUNET_ERROR_TYPE_ERROR |
573 GNUNET_ERROR_TYPE_BULK,
574 "sq_prepare");
575 goto END;
576 }
577
578 if (SQLITE_OK != sqlite3_bind_int (stmtd, 1, sizeof (GNUNET_HashCode)))
579 LOG_SQLITE (nc->plugin, NULL,
580 GNUNET_ERROR_TYPE_ERROR |
581 GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_int");
582 if (SQLITE_DONE != sqlite3_step (stmtd))
583 LOG_SQLITE (nc->plugin, NULL,
584 GNUNET_ERROR_TYPE_ERROR |
585 GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
586 if (SQLITE_OK != sqlite3_finalize (stmtd))
587 LOG_SQLITE (nc->plugin, NULL,
588 GNUNET_ERROR_TYPE_ERROR |
589 GNUNET_ERROR_TYPE_BULK, "sqlite3_finalize");
590 goto END;
591 }
592
593 priority = sqlite3_column_int (nc->stmt, 2);
594 nc->lastPriority = priority;
595 anonymity = sqlite3_column_int (nc->stmt, 3);
596 expiration.value = sqlite3_column_int64 (nc->stmt, 4);
597 nc->lastExpiration = expiration;
598 key = sqlite3_column_blob (nc->stmt, 5);
599 data = sqlite3_column_blob (nc->stmt, 6);
600 nc->count++;
601 ret = nc->iter (nc->iter_cls,
602 nc,
603 key,
604 size,
605 data,
606 type,
607 priority,
608 anonymity,
609 expiration,
610 rowid);
611 if (ret == GNUNET_SYSERR)
612 {
613 nc->end_it = GNUNET_YES;
614 return;
615 }
616 if ( (ret == GNUNET_NO) &&
617 (GNUNET_OK == delete_by_rowid (plugin, rowid)) )
618 {
619 plugin->payload -= (size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
620 plugin->lastSync++;
621 if (plugin->lastSync >= MAX_STAT_SYNC_LAG)
622 sync_stats (plugin);
623 }
71} 624}
72 625
73 626
@@ -96,37 +649,76 @@ sqlite_plugin_put (void *cls,
96 struct GNUNET_TIME_Absolute expiration, 649 struct GNUNET_TIME_Absolute expiration,
97 char ** msg) 650 char ** msg)
98{ 651{
99 *msg = GNUNET_strdup("not implemented"); 652 struct Plugin *plugin = cls;
100 return GNUNET_SYSERR; 653 int n;
101} 654 sqlite3_stmt *stmt;
655 GNUNET_HashCode vhash;
102 656
657#if DEBUG_SQLITE
658 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
659 "sqlite",
660 "Storing in database block with type %u/key `%s'/priority %u/expiration %llu.\n",
661 type,
662 GNUNET_h2s(key),
663 priority,
664 GNUNET_TIME_absolute_get_remaining (expiration).value);
665#endif
666 GNUNET_CRYPTO_hash (data, size, &vhash);
667 stmt = plugin->insertContent;
668 if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, size)) ||
669 (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
670 (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) ||
671 (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) ||
672 (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.value)) ||
673 (SQLITE_OK !=
674 sqlite3_bind_blob (stmt, 6, key, sizeof (GNUNET_HashCode),
675 SQLITE_TRANSIENT)) ||
676 (SQLITE_OK !=
677 sqlite3_bind_blob (stmt, 7, &vhash, sizeof (GNUNET_HashCode),
678 SQLITE_TRANSIENT))
679 || (SQLITE_OK !=
680 sqlite3_bind_blob (stmt, 8, data, size,
681 SQLITE_TRANSIENT)))
682 {
683 LOG_SQLITE (plugin,
684 msg,
685 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX");
686 if (SQLITE_OK != sqlite3_reset (stmt))
687 LOG_SQLITE (plugin, NULL,
688 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
689 return GNUNET_SYSERR;
690 }
103 691
104/** 692 n = sqlite3_step (stmt);
105 * Iterate over the results for a particular key 693 if (n != SQLITE_DONE)
106 * in the datastore. 694 {
107 * 695 if (n == SQLITE_BUSY)
108 * @param cls closure 696 {
109 * @param key maybe NULL (to match all entries) 697 LOG_SQLITE (plugin, msg,
110 * @param vhash hash of the value, maybe NULL (to 698 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
111 * match all values that have the right key). 699 sqlite3_reset (stmt);
112 * Note that for DBlocks there is no difference 700 GNUNET_break (0);
113 * betwen key and vhash, but for other blocks 701 return GNUNET_NO;
114 * there may be! 702 }
115 * @param type entries of which type are relevant? 703 LOG_SQLITE (plugin, msg,
116 * Use 0 for any type. 704 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step");
117 * @param iter function to call on each matching value; 705 sqlite3_reset (stmt);
118 * will be called once with a NULL value at the end 706 return GNUNET_SYSERR;
119 * @param iter_cls closure for iter 707 }
120 */ 708 if (SQLITE_OK != sqlite3_reset (stmt))
121static void 709 LOG_SQLITE (plugin, NULL,
122sqlite_plugin_get (void *cls, 710 GNUNET_ERROR_TYPE_ERROR |
123 const GNUNET_HashCode * key, 711 GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
124 const GNUNET_HashCode * vhash, 712 plugin->lastSync++;
125 uint32_t type, 713 plugin->payload += size + GNUNET_DATASTORE_ENTRY_OVERHEAD;
126 PluginIterator iter, void *iter_cls) 714 if (plugin->lastSync >= MAX_STAT_SYNC_LAG)
127{ 715 sync_stats (plugin);
128 static struct GNUNET_TIME_Absolute zero; 716#if DEBUG_SQLITE
129 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0); 717 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
718 "sqlite",
719 "done writing content\n");
720#endif
721 return GNUNET_OK;
130} 722}
131 723
132 724
@@ -158,8 +750,281 @@ sqlite_plugin_update (void *cls,
158 int delta, struct GNUNET_TIME_Absolute expire, 750 int delta, struct GNUNET_TIME_Absolute expire,
159 char **msg) 751 char **msg)
160{ 752{
161 *msg = GNUNET_strdup ("not implemented"); 753 struct Plugin *plugin = cls;
162 return GNUNET_SYSERR; 754 int n;
755
756 sqlite3_bind_int (plugin->updPrio, 1, delta);
757 sqlite3_bind_int64 (plugin->updPrio, 2, expire.value);
758 sqlite3_bind_int64 (plugin->updPrio, 3, uid);
759 n = sqlite3_step (plugin->updPrio);
760 if (n != SQLITE_OK)
761 LOG_SQLITE (plugin, msg,
762 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
763 "sqlite3_step");
764#if DEBUG_SQLITE
765 else
766 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
767 "sqlite",
768 "Block updated\n");
769#endif
770 sqlite3_reset (plugin->updPrio);
771
772 if (n == SQLITE_BUSY)
773 return GNUNET_NO;
774 return n == SQLITE_OK ? GNUNET_OK : GNUNET_SYSERR;
775}
776
777
778struct IterContext
779{
780 sqlite3_stmt *stmt_1;
781 sqlite3_stmt *stmt_2;
782 int is_asc;
783 int is_prio;
784 int is_migr;
785 int limit_nonanonymous;
786 uint32_t type;
787 GNUNET_HashCode key;
788};
789
790
791static int
792iter_next_prepare (void *cls,
793 struct NextContext *nc)
794{
795 struct IterContext *ic = cls;
796 struct Plugin *plugin = nc->plugin;
797 struct GNUNET_TIME_Absolute now;
798
799 if (nc == NULL)
800 {
801 sqlite3_finalize (ic->stmt_1);
802 sqlite3_finalize (ic->stmt_2);
803 return GNUNET_SYSERR;
804 }
805 now = GNUNET_TIME_absolute_get ();
806 if (ic->is_prio)
807 {
808 sqlite3_bind_int (ic->stmt_1, 1, nc->lastPriority);
809 sqlite3_bind_int (ic->stmt_2, 1, nc->lastPriority);
810 }
811 else
812 {
813 sqlite3_bind_int64 (ic->stmt_1, 1, nc->lastExpiration.value);
814 sqlite3_bind_int64 (ic->stmt_2, 1, nc->lastExpiration.value);
815 }
816 sqlite3_bind_blob (ic->stmt_1, 2,
817 &ic->key,
818 sizeof (GNUNET_HashCode),
819 SQLITE_TRANSIENT);
820 datum_1 = NULL;
821 datum_2 = last_datum_2;
822 last_datum_2 = NULL;
823
824 if ( (SQLITE_ROW == (ret = sqlite3_step (stmt_1))) &&
825 ( (GNUNET_NO == ic->is_migr) ||
826 (sqlite3_column_int64 (stmt_1, 4) >= now.value) ) )
827 {
828 nc->stmt = ic->stmt_1;
829 return GNUNET_OK;
830 }
831 if (ret != SQLITE_DONE)
832 {
833 LOG_SQLITE (plugin, NULL,
834 GNUNET_ERROR_TYPE_ERROR |
835 GNUNET_ERROR_TYPE_BULK,
836 "sqlite3_step");
837 return GNUNET_SYSERR;
838 }
839 if (SQLITE_OK != sqlite3_reset (stmt_1))
840 LOG_SQLITE (handle, NULL,
841 GNUNET_ERROR_TYPE_ERROR |
842 GNUNET_ERROR_TYPE_BULK,
843 "sqlite3_reset");
844
845 if (datum_2 == NULL)
846 {
847 if ( (SQLITE_ROW == (ret = sqlite3_step (ic->stmt_2))) &&
848 ( (GNUNET_NO == ic->is_migr) ||
849 sqlite3_column_int64 (stmt_2, 4) >= now.value) )
850 {
851 nc->stmt = ic->stmt_2;
852 return GNUNET_OK;
853 }
854 if (ret != SQLITE_DONE)
855 {
856 LOG_SQLITE (plugin, NULL,
857 GNUNET_ERROR_TYPE_ERROR |
858 GNUNET_ERROR_TYPE_BULK,
859 "sqlite3_step");
860 return GNUNET_SYSERR;
861 }
862 if (SQLITE_OK != sqlite3_reset (stmt_2))
863 LOG_SQLITE (plugin, NULL,
864 GNUNET_ERROR_TYPE_ERROR |
865 GNUNET_ERROR_TYPE_BULK,
866 "sqlite3_reset");
867 }
868 datum = NULL;
869 if (datum_1 == NULL)
870 {
871 datum = datum_2;
872 rowid = rowid_2;
873 key = key_2;
874 }
875 else if (datum_2 == NULL)
876 {
877 datum = datum_1;
878 rowid = rowid_1;
879 key = key_1;
880 }
881 else
882 {
883 /* have to pick between 1 and 2 */
884 if (is_prio)
885 {
886 if ((ntohl (datum_1->priority) < ntohl (datum_2->priority)) ==
887 is_asc)
888 {
889 datum = datum_1;
890 rowid = rowid_1;
891 key = key_1;
892 last_datum_2 = datum_2;
893 }
894 else
895 {
896 datum = datum_2;
897 rowid = rowid_2;
898 key = key_2;
899 GNUNET_free (datum_1);
900 }
901 }
902 else
903 {
904 if ((GNUNET_ntohll (datum_1->expiration_time) <
905 GNUNET_ntohll (datum_2->expiration_time)) == is_asc)
906 {
907 datum = datum_1;
908 rowid = rowid_1;
909 key = key_1;
910 last_datum_2 = datum_2;
911 }
912 else
913 {
914 datum = datum_2;
915 rowid = rowid_2;
916 key = key_2;
917 GNUNET_free (datum_1);
918 }
919 }
920 }
921 if (datum == NULL)
922 break;
923#if 0
924 printf ("FOUND %4u prio %4u exp %20llu old: %4u, %20llu\n",
925 (ntohl (datum->size) - sizeof (GNUNET_DatastoreValue)),
926 ntohl (datum->priority),
927 GNUNET_ntohll (datum->expiration_time), lastPrio, lastExp);
928#endif
929 if (((GNUNET_NO == limit_nonanonymous) ||
930 (ntohl (datum->anonymity_level) == 0)) &&
931 ((type == GNUNET_ECRS_BLOCKTYPE_ANY) ||
932 (type == ntohl (datum->type))))
933 {
934 count++;
935 if (iter != NULL)
936 {
937 ret = iter (&key, datum, closure, rowid);
938 if (ret == GNUNET_SYSERR)
939 {
940 GNUNET_free (datum);
941 break;
942 }
943 if (ret == GNUNET_NO)
944 {
945 payload -= getContentDatastoreSize (datum);
946 delete_by_rowid (handle, rowid);
947 }
948 }
949 }
950}
951
952
953/**
954 * Call a method for each key in the database and
955 * call the callback method on it.
956 *
957 * @param type entries of which type should be considered?
958 * @param iter function to call on each matching value;
959 * will be called once with a NULL value at the end
960 * @param iter_cls closure for iter
961 * @return the number of results processed,
962 * GNUNET_SYSERR on error
963 */
964static void
965basic_iter (struct Plugin *plugin,
966 uint32_t type,
967 int is_asc,
968 int is_prio,
969 int is_migr,
970 int limit_nonanonymous,
971 const char *stmt_str_1,
972 const char *stmt_str_2,
973 PluginIterator iter,
974 void *iter_cls)
975{
976 static struct GNUNET_TIME_Absolute zero;
977 struct NextContext *nc;
978 struct IterContext *ic;
979 sqlite3_stmt *stmt_1;
980 sqlite3_stmt *stmt_2;
981
982 if (sq_prepare (plugin->dbh, stmt_str_1, &stmt_1) != SQLITE_OK)
983 {
984 LOG_SQLITE (plugin, NULL,
985 GNUNET_ERROR_TYPE_ERROR |
986 GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare");
987 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
988 return;
989 }
990 if (sq_prepare (plugin->dbh, stmt_str_2, &stmt_2) != SQLITE_OK)
991 {
992 LOG_SQLITE (plugin, NULL,
993 GNUNET_ERROR_TYPE_ERROR |
994 GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare");
995 sqlite3_finalize (stmt_1);
996 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
997 return;
998 }
999 nc = GNUNET_malloc (sizeof(struct NextContext) +
1000 sizeof(struct IterContext));
1001 nc->plugin = plugin;
1002 nc->iter = iter;
1003 nc->iter_cls = iter_cls;
1004 nc->stmt = NULL;
1005 ic = (struct IterContext*) &nc[1];
1006 ic->stmt_1 = stmt_1;
1007 ic->stmt_2 = stmt_2;
1008 ic->type = type;
1009 ic->is_asc = is_asc;
1010 ic->is_prio = is_prio;
1011 ic->is_migr = is_migr;
1012 ic->limit_nonanonymous = limit_nonanonymous;
1013 nc->prep = &iter_next_prepare;
1014 nc->prep_cls = ic;
1015 if (is_asc)
1016 {
1017 nc->lastPriority = 0;
1018 nc->lastExpiration.value = 0;
1019 memset (&ic->key, 0, sizeof (GNUNET_HashCode));
1020 }
1021 else
1022 {
1023 nc->lastPriority = 0x7FFFFFFF;
1024 nc->lastExpiration.value = 0x7FFFFFFFFFFFFFFFLL;
1025 memset (&ic->key, 255, sizeof (GNUNET_HashCode));
1026 }
1027 sqlite_next_request (nc, GNUNET_NO);
163} 1028}
164 1029
165 1030
@@ -179,8 +1044,13 @@ sqlite_plugin_iter_low_priority (void *cls,
179 PluginIterator iter, 1044 PluginIterator iter,
180 void *iter_cls) 1045 void *iter_cls)
181{ 1046{
182 static struct GNUNET_TIME_Absolute zero; 1047 basic_iter (cls,
183 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0); 1048 type,
1049 GNUNET_YES, GNUNET_YES,
1050 GNUNET_NO, GNUNET_NO,
1051 SELECT_IT_LOW_PRIORITY_1,
1052 SELECT_IT_LOW_PRIORITY_2,
1053 iter, iter_cls);
184} 1054}
185 1055
186 1056
@@ -271,29 +1141,262 @@ sqlite_plugin_iter_all_now (void *cls,
271} 1141}
272 1142
273 1143
1144struct GetNextContext
1145{
1146 int total;
1147 int off;
1148 int have_vhash;
1149 unsigned int type;
1150 sqlite3_stmt *stmt;
1151 GNUNET_HashCode key;
1152 GNUNET_HashCode vhash;
1153};
1154
1155
1156static int
1157get_next_prepare (void *cls,
1158 struct NextContext *nc)
1159{
1160 struct GetNextContext *gnc = cls;
1161 int sqoff;
1162 int ret;
1163 int limit_off;
1164
1165 if (nc == NULL)
1166 {
1167 sqlite3_finalize (gnc->stmt);
1168 return GNUNET_SYSERR;
1169 }
1170 if (nc->count == gnc->total)
1171 return GNUNET_NO;
1172 if (nc->count + gnc->off == gnc->total)
1173 nc->last_rowid = 0;
1174 if (nc->count == 0)
1175 limit_off = gnc->off;
1176 else
1177 limit_off = 0;
1178 sqoff = 1;
1179 ret = sqlite3_bind_blob (nc->stmt,
1180 sqoff++,
1181 &gnc->key,
1182 sizeof (GNUNET_HashCode),
1183 SQLITE_TRANSIENT);
1184 if ((gnc->have_vhash) && (ret == SQLITE_OK))
1185 ret = sqlite3_bind_blob (nc->stmt,
1186 sqoff++,
1187 &gnc->vhash,
1188 sizeof (GNUNET_HashCode), SQLITE_TRANSIENT);
1189 if ((gnc->type != 0) && (ret == SQLITE_OK))
1190 ret = sqlite3_bind_int (nc->stmt, sqoff++, gnc->type);
1191 if (ret == SQLITE_OK)
1192 ret = sqlite3_bind_int64 (nc->stmt, sqoff++, nc->last_rowid + 1);
1193 if (ret == SQLITE_OK)
1194 ret = sqlite3_bind_int (nc->stmt, sqoff++, limit_off);
1195 if (ret != SQLITE_OK)
1196 return GNUNET_SYSERR;
1197 if (SQLITE_ROW != sqlite3_step (nc->stmt))
1198 return GNUNET_NO;
1199 return GNUNET_OK;
1200}
1201
1202
1203/**
1204 * Iterate over the results for a particular key
1205 * in the datastore.
1206 *
1207 * @param cls closure
1208 * @param key maybe NULL (to match all entries)
1209 * @param vhash hash of the value, maybe NULL (to
1210 * match all values that have the right key).
1211 * Note that for DBlocks there is no difference
1212 * betwen key and vhash, but for other blocks
1213 * there may be!
1214 * @param type entries of which type are relevant?
1215 * Use 0 for any type.
1216 * @param iter function to call on each matching value;
1217 * will be called once with a NULL value at the end
1218 * @param iter_cls closure for iter
1219 */
1220static void
1221sqlite_plugin_get (void *cls,
1222 const GNUNET_HashCode * key,
1223 const GNUNET_HashCode * vhash,
1224 uint32_t type,
1225 PluginIterator iter, void *iter_cls)
1226{
1227 static struct GNUNET_TIME_Absolute zero;
1228 struct Plugin *plugin = cls;
1229 struct GetNextContext *gpc;
1230 struct NextContext *nc;
1231 int ret;
1232 int total;
1233 sqlite3_stmt *stmt;
1234 char scratch[256];
1235 int sqoff;
1236
1237 GNUNET_assert (iter != NULL);
1238 if (key == NULL)
1239 {
1240 sqlite_plugin_iter_low_priority (cls, type, iter, iter_cls);
1241 return;
1242 }
1243 GNUNET_snprintf (scratch, 256,
1244 "SELECT count(*) FROM gn080 WHERE hash=:1%s%s",
1245 vhash == NULL ? "" : " AND vhash=:2",
1246 type == 0 ? "" : (vhash ==
1247 NULL) ? " AND type=:2" : " AND type=:3");
1248 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
1249 {
1250 LOG_SQLITE (plugin, NULL,
1251 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite_prepare");
1252 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
1253 return;
1254 }
1255 sqoff = 1;
1256 ret = sqlite3_bind_blob (stmt,
1257 sqoff++,
1258 key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT);
1259 if ((vhash != NULL) && (ret == SQLITE_OK))
1260 ret = sqlite3_bind_blob (stmt,
1261 sqoff++,
1262 vhash,
1263 sizeof (GNUNET_HashCode), SQLITE_TRANSIENT);
1264 if ((type != 0) && (ret == SQLITE_OK))
1265 ret = sqlite3_bind_int (stmt, sqoff++, type);
1266 if (SQLITE_OK != ret)
1267 {
1268 LOG_SQLITE (plugin, NULL,
1269 GNUNET_ERROR_TYPE_ERROR, "sqlite_bind");
1270 sqlite3_reset (stmt);
1271 sqlite3_finalize (stmt);
1272 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
1273 return;
1274 }
1275 ret = sqlite3_step (stmt);
1276 if (ret != SQLITE_ROW)
1277 {
1278 LOG_SQLITE (plugin, NULL,
1279 GNUNET_ERROR_TYPE_ERROR| GNUNET_ERROR_TYPE_BULK,
1280 "sqlite_step");
1281 sqlite3_reset (stmt);
1282 sqlite3_finalize (stmt);
1283 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
1284 return;
1285 }
1286 total = sqlite3_column_int (stmt, 0);
1287 sqlite3_reset (stmt);
1288 sqlite3_finalize (stmt);
1289 if (0 == total)
1290 {
1291 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
1292 return;
1293 }
1294
1295 GNUNET_snprintf (scratch, 256,
1296 "SELECT size, type, prio, anonLevel, expire, hash, value, _ROWID_ "
1297 "FROM gn080 WHERE hash=:1%s%s AND _ROWID_ >= :%d "
1298 "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET :d",
1299 vhash == NULL ? "" : " AND vhash=:2",
1300 type == 0 ? "" : (vhash ==
1301 NULL) ? " AND type=:2" : " AND type=:3",
1302 sqoff, sqoff + 1);
1303 if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
1304 {
1305 LOG_SQLITE (plugin, NULL,
1306 GNUNET_ERROR_TYPE_ERROR |
1307 GNUNET_ERROR_TYPE_BULK, "sqlite_prepare");
1308 iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, zero, 0);
1309 return;
1310 }
1311 nc = GNUNET_malloc (sizeof(struct NextContext) +
1312 sizeof(struct GetNextContext));
1313 nc->plugin = plugin;
1314 nc->iter = iter;
1315 nc->iter_cls = iter_cls;
1316 nc->stmt = stmt;
1317 gpc = (struct GetNextContext*) &nc[1];
1318 gpc->total = total;
1319 gpc->type = type;
1320 gpc->key = *key;
1321 gpc->stmt = stmt; /* alias used for freeing at the end! */
1322 if (NULL != vhash)
1323 {
1324 gpc->have_vhash = GNUNET_YES;
1325 gpc->vhash = *vhash;
1326 }
1327 gpc->off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
1328 nc->prep = &get_next_prepare;
1329 nc->prep_cls = gpc;
1330 sqlite_next_request (nc, GNUNET_NO);
1331}
1332
1333
274/** 1334/**
275 * Drop database. 1335 * Drop database.
276 */ 1336 */
277static void 1337static void
278sqlite_plugin_drop (void *cls) 1338sqlite_plugin_drop (void *cls)
279{ 1339{
1340 struct Plugin *plugin = cls;
1341 plugin->drop_on_shutdown = GNUNET_YES;
280} 1342}
281 1343
282 1344
283/** 1345/**
1346 * Callback function to process statistic values.
1347 *
1348 * @param cls closure
1349 * @param subsystem name of subsystem that created the statistic
1350 * @param name the name of the datum
1351 * @param value the current value
1352 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
1353 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
1354 */
1355static int
1356process_stat_in (void *cls,
1357 const char *subsystem,
1358 const char *name,
1359 unsigned long long value,
1360 int is_persistent)
1361{
1362 struct Plugin *plugin = cls;
1363 plugin->payload += value;
1364 return GNUNET_OK;
1365}
1366
1367
1368/**
284 * Entry point for the plugin. 1369 * Entry point for the plugin.
285 */ 1370 */
286void * 1371void *
287libgnunet_plugin_datastore_sqlite_init (void *cls) 1372libgnunet_plugin_datastore_sqlite_init (void *cls)
288{ 1373{
1374 static struct Plugin plugin;
289 struct GNUNET_DATASTORE_PluginEnvironment *env = cls; 1375 struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
290 struct GNUNET_DATASTORE_PluginFunctions *api; 1376 struct GNUNET_DATASTORE_PluginFunctions *api;
291 struct Plugin *plugin;
292 1377
293 plugin = GNUNET_malloc (sizeof (struct Plugin)); 1378 if (plugin.env != NULL)
294 plugin->env = env; 1379 return NULL; /* can only initialize once! */
1380 memset (&plugin, 0, sizeof(struct Plugin));
1381 plugin.env = env;
1382 plugin.statistics = GNUNET_STATISTICS_create (env->sched,
1383 "sqlite",
1384 env->cfg);
1385 GNUNET_STATISTICS_get (plugin.statistics,
1386 "sqlite",
1387 QUOTA_STAT_NAME,
1388 GNUNET_TIME_UNIT_MINUTES,
1389 NULL,
1390 &process_stat_in,
1391 &plugin);
1392 if (GNUNET_OK !=
1393 database_setup (env->cfg, &plugin))
1394 {
1395 database_shutdown (&plugin);
1396 return NULL;
1397 }
295 api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); 1398 api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions));
296 api->cls = plugin; 1399 api->cls = &plugin;
297 api->get_size = &sqlite_plugin_get_size; 1400 api->get_size = &sqlite_plugin_get_size;
298 api->put = &sqlite_plugin_put; 1401 api->put = &sqlite_plugin_put;
299 api->next_request = &sqlite_next_request; 1402 api->next_request = &sqlite_next_request;
@@ -317,11 +1420,25 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
317void * 1420void *
318libgnunet_plugin_datastore_sqlite_done (void *cls) 1421libgnunet_plugin_datastore_sqlite_done (void *cls)
319{ 1422{
1423 char *fn;
320 struct GNUNET_DATASTORE_PluginFunctions *api = cls; 1424 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
321 struct Plugin *plugin = api->cls; 1425 struct Plugin *plugin = api->cls;
322 1426
323 GNUNET_free (plugin); 1427 fn = NULL;
1428 if (plugin->drop_on_shutdown)
1429 fn = GNUNET_strdup (plugin->fn);
1430 database_shutdown (plugin);
1431 plugin->env = NULL;
1432 plugin->payload = 0;
324 GNUNET_free (api); 1433 GNUNET_free (api);
1434 if (fn != NULL)
1435 {
1436 if (0 != UNLINK(fn))
1437 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1438 "unlink",
1439 fn);
1440 GNUNET_free (fn);
1441 }
325 return NULL; 1442 return NULL;
326} 1443}
327 1444