Merge branch 'master' of gnunet.org:gnunet
[oweals/gnunet.git] / src / datacache / plugin_datacache_sqlite.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2006, 2009, 2015 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
19 /**
20  * @file datacache/plugin_datacache_sqlite.c
21  * @brief sqlite for an implementation of a database backend for the datacache
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_datacache_plugin.h"
27 #include "gnunet_sq_lib.h"
28 #include <sqlite3.h>
29
30 #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
31
32 #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
33
34
35 /**
36  * How much overhead do we assume per entry in the
37  * datacache?
38  */
39 #define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
40
41 /**
42  * Context for all functions in this plugin.
43  */
44 struct Plugin
45 {
46   /**
47    * Our execution environment.
48    */
49   struct GNUNET_DATACACHE_PluginEnvironment *env;
50
51   /**
52    * Handle to the sqlite database.
53    */
54   sqlite3 *dbh;
55
56   /**
57    * Filename used for the DB.
58    */
59   char *fn;
60
61   /**
62    * Prepared statement for #sqlite_plugin_put.
63    */
64   sqlite3_stmt *insert_stmt;
65
66   /**
67    * Prepared statement for #sqlite_plugin_get.
68    */
69   sqlite3_stmt *get_count_stmt;
70
71   /**
72    * Prepared statement for #sqlite_plugin_get.
73    */
74   sqlite3_stmt *get_stmt;
75
76   /**
77    * Prepared statement for #sqlite_plugin_del.
78    */
79   sqlite3_stmt *del_select_stmt;
80
81   /**
82    * Prepared statement for #sqlite_plugin_del.
83    */
84   sqlite3_stmt *del_expired_stmt;
85
86   /**
87    * Prepared statement for #sqlite_plugin_del.
88    */
89   sqlite3_stmt *del_stmt;
90
91   /**
92    * Prepared statement for #sqlite_plugin_get_random.
93    */
94   sqlite3_stmt *get_random_stmt;
95
96   /**
97    * Prepared statement for #sqlite_plugin_get_closest.
98    */
99   sqlite3_stmt *get_closest_stmt;
100
101   /**
102    * Number of key-value pairs in the database.
103    */
104   unsigned int num_items;
105 };
106
107
108 /**
109  * Log an error message at log-level @a level that indicates
110  * a failure of the command @a cmd with the error from the database @a db
111  *
112  * @param db database handle
113  * @param level log level
114  * @param cmd failed command
115  */
116 #define LOG_SQLITE(db, level, cmd) do { LOG (level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0)
117
118
119 /**
120  * Execute SQL statement.
121  *
122  * @param db database handle
123  * @param cmd SQL command to execute
124  */
125 #define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0)
126
127
128 /**
129  * @brief Prepare a SQL statement
130  *
131  * @param dbh database handle
132  * @param zsql SQL statement text
133  * @param[out] ppStmt set to the prepared statement
134  * @return 0 on success
135  */
136 static int
137 sq_prepare (sqlite3 *dbh,
138             const char *zSql,    /* SQL statement, UTF-8 encoded */
139             sqlite3_stmt **ppStmt)
140 {                               /* OUT: Statement handle */
141   char *dummy;
142
143   return sqlite3_prepare (dbh,
144                           zSql,
145                           strlen (zSql),
146                           ppStmt,
147                           (const char **) &dummy);
148 }
149
150
151 /**
152  * Store an item in the datastore.
153  *
154  * @param cls closure (our `struct Plugin`)
155  * @param key key to store @a data under
156  * @param xor_distance how close is @a key to our PID?
157  * @param size number of bytes in @a data
158  * @param data data to store
159  * @param type type of the value
160  * @param discard_time when to discard the value in any case
161  * @param path_info_len number of entries in @a path_info
162  * @param path_info array of peers that have processed the request
163  * @return 0 if duplicate, -1 on error, number of bytes used otherwise
164  */
165 static ssize_t
166 sqlite_plugin_put (void *cls,
167                    const struct GNUNET_HashCode *key,
168                    uint32_t xor_distance,
169                    size_t size,
170                    const char *data,
171                    enum GNUNET_BLOCK_Type type,
172                    struct GNUNET_TIME_Absolute discard_time,
173                    unsigned int path_info_len,
174                    const struct GNUNET_PeerIdentity *path_info)
175 {
176   struct Plugin *plugin = cls;
177   uint32_t type32 = type;
178   struct GNUNET_SQ_QueryParam params[] = {
179     GNUNET_SQ_query_param_uint32 (&type32),
180     GNUNET_SQ_query_param_absolute_time (&discard_time),
181     GNUNET_SQ_query_param_auto_from_type (key),
182     GNUNET_SQ_query_param_uint32 (&xor_distance),
183     GNUNET_SQ_query_param_fixed_size (data, size),
184     GNUNET_SQ_query_param_fixed_size (path_info,
185                                       path_info_len * sizeof (struct GNUNET_PeerIdentity)),
186     GNUNET_SQ_query_param_end
187   };
188
189   LOG (GNUNET_ERROR_TYPE_DEBUG,
190        "Processing PUT of %u bytes with key `%s' and expiration %s\n",
191        (unsigned int) size,
192        GNUNET_h2s (key),
193        GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
194                                                GNUNET_YES));
195   if (GNUNET_OK !=
196       GNUNET_SQ_bind (plugin->insert_stmt,
197                       params))
198   {
199     LOG_SQLITE (plugin->dbh,
200                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
201                 "sqlite3_bind_xxx");
202     GNUNET_SQ_reset (plugin->dbh,
203                      plugin->insert_stmt);
204     return -1;
205   }
206   if (SQLITE_DONE !=
207       sqlite3_step (plugin->insert_stmt))
208   {
209     LOG_SQLITE (plugin->dbh,
210                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
211                 "sqlite3_step");
212     GNUNET_SQ_reset (plugin->dbh,
213                      plugin->insert_stmt);
214     return -1;
215   }
216   plugin->num_items++;
217   GNUNET_SQ_reset (plugin->dbh,
218                    plugin->insert_stmt);
219   return size + OVERHEAD;
220 }
221
222
223 /**
224  * Iterate over the results for a particular key
225  * in the datastore.
226  *
227  * @param cls closure (our `struct Plugin`)
228  * @param key
229  * @param type entries of which type are relevant?
230  * @param iter maybe NULL (to just count)
231  * @param iter_cls closure for @a iter
232  * @return the number of results found
233  */
234 static unsigned int
235 sqlite_plugin_get (void *cls,
236                    const struct GNUNET_HashCode *key,
237                    enum GNUNET_BLOCK_Type type,
238                    GNUNET_DATACACHE_Iterator iter,
239                    void *iter_cls)
240 {
241   struct Plugin *plugin = cls;
242   uint32_t type32 = type;
243   struct GNUNET_TIME_Absolute now;
244   struct GNUNET_TIME_Absolute exp;
245   size_t size;
246   void *dat;
247   unsigned int cnt;
248   uint32_t off;
249   unsigned int total;
250   size_t psize;
251   struct GNUNET_PeerIdentity *path;
252   struct GNUNET_SQ_QueryParam params_count[] = {
253     GNUNET_SQ_query_param_auto_from_type (key),
254     GNUNET_SQ_query_param_uint32 (&type32),
255     GNUNET_SQ_query_param_absolute_time (&now),
256     GNUNET_SQ_query_param_end
257   };
258   struct GNUNET_SQ_QueryParam params_select[] = {
259     GNUNET_SQ_query_param_auto_from_type (key),
260     GNUNET_SQ_query_param_uint32 (&type32),
261     GNUNET_SQ_query_param_absolute_time (&now),
262     GNUNET_SQ_query_param_uint32 (&off),
263     GNUNET_SQ_query_param_end
264   };
265   struct GNUNET_SQ_ResultSpec rs[] = {
266     GNUNET_SQ_result_spec_variable_size (&dat,
267                                          &size),
268     GNUNET_SQ_result_spec_absolute_time (&exp),
269     GNUNET_SQ_result_spec_variable_size ((void **) &path,
270                                          &psize),
271     GNUNET_SQ_result_spec_end
272   };
273
274   now = GNUNET_TIME_absolute_get ();
275   LOG (GNUNET_ERROR_TYPE_DEBUG,
276        "Processing GET for key `%s'\n",
277        GNUNET_h2s (key));
278
279   if (GNUNET_OK !=
280       GNUNET_SQ_bind (plugin->get_count_stmt,
281                       params_count))
282   {
283     LOG_SQLITE (plugin->dbh,
284                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
285                 "sqlite3_bind_xxx");
286     GNUNET_SQ_reset (plugin->dbh,
287                      plugin->get_count_stmt);
288     return 0;
289   }
290   if (SQLITE_ROW !=
291       sqlite3_step (plugin->get_count_stmt))
292   {
293     LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
294                 "sqlite_step");
295     GNUNET_SQ_reset (plugin->dbh,
296                      plugin->get_count_stmt);
297     LOG (GNUNET_ERROR_TYPE_DEBUG,
298          "No content found when processing GET for key `%s'\n",
299          GNUNET_h2s (key));
300     return 0;
301   }
302   total = sqlite3_column_int (plugin->get_count_stmt,
303                               0);
304   GNUNET_SQ_reset (plugin->dbh,
305                    plugin->get_count_stmt);
306   if ( (0 == total) ||
307        (NULL == iter) )
308   {
309     if (0 == total)
310       LOG (GNUNET_ERROR_TYPE_DEBUG,
311            "No content found when processing GET for key `%s'\n",
312            GNUNET_h2s (key));
313     return total;
314   }
315
316   cnt = 0;
317   off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
318                                   total);
319   while (cnt < total)
320   {
321     off = (off + 1) % total;
322     if (GNUNET_OK !=
323         GNUNET_SQ_bind (plugin->get_stmt,
324                         params_select))
325     {
326       LOG_SQLITE (plugin->dbh,
327                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
328                   "sqlite3_bind_xxx");
329       GNUNET_SQ_reset (plugin->dbh,
330                        plugin->get_stmt);
331       return cnt;
332     }
333     if (SQLITE_ROW !=
334         sqlite3_step (plugin->get_stmt))
335       break;
336     if (GNUNET_OK !=
337         GNUNET_SQ_extract_result (plugin->get_stmt,
338                                   rs))
339     {
340       GNUNET_break (0);
341       GNUNET_SQ_reset (plugin->dbh,
342                        plugin->get_stmt);
343       break;
344     }
345     if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
346     {
347       GNUNET_break (0);
348       psize = 0;
349       path = NULL;
350     }
351     psize /= sizeof (struct GNUNET_PeerIdentity);
352     cnt++;
353     LOG (GNUNET_ERROR_TYPE_DEBUG,
354          "Found %u-byte result when processing GET for key `%s'\n",
355          (unsigned int) size,
356          GNUNET_h2s (key));
357     if (GNUNET_OK != iter (iter_cls,
358                            key,
359                            size,
360                            dat,
361                            type,
362                            exp,
363                            psize,
364                            path))
365     {
366       GNUNET_SQ_cleanup_result (rs);
367       GNUNET_SQ_reset (plugin->dbh,
368                        plugin->get_stmt);
369       break;
370     }
371     GNUNET_SQ_cleanup_result (rs);
372     GNUNET_SQ_reset (plugin->dbh,
373                      plugin->get_stmt);
374   }
375   GNUNET_SQ_reset (plugin->dbh,
376                    plugin->get_stmt);
377   return cnt;
378 }
379
380
381 /**
382  * Delete the entry with the lowest expiration value
383  * from the datacache right now.
384  *
385  * @param cls closure (our `struct Plugin`)
386  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
387  */
388 static int
389 sqlite_plugin_del (void *cls)
390 {
391   struct Plugin *plugin = cls;
392   uint64_t rowid;
393   void *data;
394   size_t dsize;
395   struct GNUNET_HashCode hc;
396   struct GNUNET_TIME_Absolute now;
397   struct GNUNET_SQ_ResultSpec rs[] = {
398     GNUNET_SQ_result_spec_uint64 (&rowid),
399     GNUNET_SQ_result_spec_auto_from_type (&hc),
400     GNUNET_SQ_result_spec_variable_size ((void **) &data,
401                                          &dsize),
402     GNUNET_SQ_result_spec_end
403   };
404   struct GNUNET_SQ_QueryParam params[] = {
405     GNUNET_SQ_query_param_uint64 (&rowid),
406     GNUNET_SQ_query_param_end
407   };
408   struct GNUNET_SQ_QueryParam time_params[] = {
409     GNUNET_SQ_query_param_absolute_time (&now),
410     GNUNET_SQ_query_param_end
411   };
412
413   LOG (GNUNET_ERROR_TYPE_DEBUG,
414        "Processing DEL\n");
415   now = GNUNET_TIME_absolute_get ();
416   if (GNUNET_OK !=
417       GNUNET_SQ_bind (plugin->del_expired_stmt,
418                       time_params))
419   {
420     LOG_SQLITE (plugin->dbh,
421                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
422                 "sqlite3_bind");
423     GNUNET_SQ_reset (plugin->dbh,
424                      plugin->del_expired_stmt);
425     return GNUNET_SYSERR;
426   }
427   if ( (SQLITE_ROW !=
428         sqlite3_step (plugin->del_expired_stmt)) ||
429        (GNUNET_OK !=
430         GNUNET_SQ_extract_result (plugin->del_expired_stmt,
431                                   rs)) )
432   {
433     GNUNET_SQ_reset (plugin->dbh,
434                      plugin->del_expired_stmt);
435     if (SQLITE_ROW !=
436         sqlite3_step (plugin->del_select_stmt))
437     {
438       LOG_SQLITE (plugin->dbh,
439                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
440                   "sqlite3_step");
441       GNUNET_SQ_reset (plugin->dbh,
442                        plugin->del_select_stmt);
443       return GNUNET_SYSERR;
444     }
445     if (GNUNET_OK !=
446         GNUNET_SQ_extract_result (plugin->del_select_stmt,
447                                   rs))
448     {
449       GNUNET_SQ_reset (plugin->dbh,
450                        plugin->del_select_stmt);
451       GNUNET_break (0);
452       return GNUNET_SYSERR;
453     }
454   }
455   GNUNET_SQ_cleanup_result (rs);
456   GNUNET_SQ_reset (plugin->dbh,
457                    plugin->del_select_stmt);
458   if (GNUNET_OK !=
459       GNUNET_SQ_bind (plugin->del_stmt,
460                       params))
461   {
462     LOG_SQLITE (plugin->dbh,
463                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
464                 "sqlite3_bind");
465     GNUNET_SQ_reset (plugin->dbh,
466                      plugin->del_stmt);
467     return GNUNET_SYSERR;
468   }
469   if (SQLITE_DONE !=
470       sqlite3_step (plugin->del_stmt))
471   {
472     LOG_SQLITE (plugin->dbh,
473                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
474                 "sqlite3_step");
475     GNUNET_SQ_reset (plugin->dbh,
476                      plugin->del_stmt);
477     return GNUNET_SYSERR;
478   }
479   plugin->num_items--;
480   plugin->env->delete_notify (plugin->env->cls,
481                               &hc,
482                               dsize + OVERHEAD);
483   GNUNET_SQ_reset (plugin->dbh,
484                    plugin->del_stmt);
485   return GNUNET_OK;
486 }
487
488
489 /**
490  * Obtain a random key-value pair from the datacache.
491  *
492  * @param cls closure (our `struct Plugin`)
493  * @param iter maybe NULL (to just count)
494  * @param iter_cls closure for @a iter
495  * @return the number of results found, zero (datacache empty) or one
496  */
497 static unsigned int
498 sqlite_plugin_get_random (void *cls,
499                           GNUNET_DATACACHE_Iterator iter,
500                           void *iter_cls)
501 {
502   struct Plugin *plugin = cls;
503   struct GNUNET_TIME_Absolute exp;
504   size_t size;
505   void *dat;
506   uint32_t off;
507   size_t psize;
508   uint32_t type;
509   struct GNUNET_PeerIdentity *path;
510   struct GNUNET_HashCode key;
511   struct GNUNET_SQ_QueryParam params[] = {
512     GNUNET_SQ_query_param_uint32 (&off),
513     GNUNET_SQ_query_param_end
514   };
515   struct GNUNET_SQ_ResultSpec rs[] = {
516     GNUNET_SQ_result_spec_variable_size (&dat,
517                                          &size),
518     GNUNET_SQ_result_spec_absolute_time (&exp),
519     GNUNET_SQ_result_spec_variable_size ((void **) &path,
520                                          &psize),
521     GNUNET_SQ_result_spec_auto_from_type (&key),
522     GNUNET_SQ_result_spec_uint32 (&type),
523     GNUNET_SQ_result_spec_end
524   };
525
526   if (0 == plugin->num_items)
527     return 0;
528   if (NULL == iter)
529     return 1;
530   off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
531                                   plugin->num_items);
532   if (GNUNET_OK !=
533       GNUNET_SQ_bind (plugin->get_random_stmt,
534                       params))
535   {
536     return 0;
537   }
538   if (SQLITE_ROW !=
539       sqlite3_step (plugin->get_random_stmt))
540   {
541     GNUNET_break (0);
542     GNUNET_SQ_reset (plugin->dbh,
543                      plugin->get_random_stmt);
544     return 0;
545   }
546   if (GNUNET_OK !=
547       GNUNET_SQ_extract_result (plugin->get_random_stmt,
548                                 rs))
549   {
550     GNUNET_break (0);
551     GNUNET_SQ_reset (plugin->dbh,
552                      plugin->get_random_stmt);
553     return 0;
554   }
555   if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
556   {
557     GNUNET_break (0);
558     psize = 0;
559     path = NULL;
560   }
561   psize /= sizeof (struct GNUNET_PeerIdentity);
562   LOG (GNUNET_ERROR_TYPE_DEBUG,
563        "Found %u-byte result with key %s when processing GET-RANDOM\n",
564        (unsigned int) size,
565        GNUNET_h2s (&key));
566   (void) iter (iter_cls,
567                &key,
568                size,
569                dat,
570                (enum GNUNET_BLOCK_Type) type,
571                exp,
572                psize,
573                path);
574   GNUNET_SQ_cleanup_result (rs);
575   GNUNET_SQ_reset (plugin->dbh,
576                    plugin->get_random_stmt);
577   return 1;
578 }
579
580
581 /**
582  * Iterate over the results that are "close" to a particular key in
583  * the datacache.  "close" is defined as numerically larger than @a
584  * key (when interpreted as a circular address space), with small
585  * distance.
586  *
587  * @param cls closure (internal context for the plugin)
588  * @param key area of the keyspace to look into
589  * @param num_results number of results that should be returned to @a iter
590  * @param iter maybe NULL (to just count)
591  * @param iter_cls closure for @a iter
592  * @return the number of results found
593  */
594 static unsigned int
595 sqlite_plugin_get_closest (void *cls,
596                            const struct GNUNET_HashCode *key,
597                            unsigned int num_results,
598                            GNUNET_DATACACHE_Iterator iter,
599                            void *iter_cls)
600 {
601   struct Plugin *plugin = cls;
602   uint32_t num_results32 = num_results;
603   struct GNUNET_TIME_Absolute now;
604   struct GNUNET_TIME_Absolute exp;
605   size_t size;
606   void *dat;
607   unsigned int cnt;
608   size_t psize;
609   uint32_t type;
610   struct GNUNET_HashCode hc;
611   struct GNUNET_PeerIdentity *path;
612   struct GNUNET_SQ_QueryParam params[] = {
613     GNUNET_SQ_query_param_auto_from_type (key),
614     GNUNET_SQ_query_param_absolute_time (&now),
615     GNUNET_SQ_query_param_uint32 (&num_results32),
616     GNUNET_SQ_query_param_end
617   };
618   struct GNUNET_SQ_ResultSpec rs[] = {
619     GNUNET_SQ_result_spec_variable_size (&dat,
620                                          &size),
621     GNUNET_SQ_result_spec_absolute_time (&exp),
622     GNUNET_SQ_result_spec_variable_size ((void **) &path,
623                                          &psize),
624     GNUNET_SQ_result_spec_uint32 (&type),
625     GNUNET_SQ_result_spec_auto_from_type (&hc),
626     GNUNET_SQ_result_spec_end
627   };
628
629   now = GNUNET_TIME_absolute_get ();
630   LOG (GNUNET_ERROR_TYPE_DEBUG,
631        "Processing GET_CLOSEST for key `%s'\n",
632        GNUNET_h2s (key));
633   if (GNUNET_OK !=
634       GNUNET_SQ_bind (plugin->get_closest_stmt,
635                       params))
636   {
637     LOG_SQLITE (plugin->dbh,
638                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
639                 "sqlite3_bind_xxx");
640     GNUNET_SQ_reset (plugin->dbh,
641                      plugin->get_closest_stmt);
642     return 0;
643   }
644   cnt = 0;
645   while (SQLITE_ROW ==
646          sqlite3_step (plugin->get_closest_stmt))
647   {
648     if (GNUNET_OK !=
649         GNUNET_SQ_extract_result (plugin->get_closest_stmt,
650                                   rs))
651     {
652       GNUNET_break (0);
653       break;
654     }
655     if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
656     {
657       GNUNET_break (0);
658       psize = 0;
659       path = NULL;
660     }
661     psize /= sizeof (struct GNUNET_PeerIdentity);
662     cnt++;
663     LOG (GNUNET_ERROR_TYPE_DEBUG,
664          "Found %u-byte result at %s when processing GET_CLOSE\n",
665          (unsigned int) size,
666          GNUNET_h2s (&hc));
667     if (GNUNET_OK != iter (iter_cls,
668                            &hc,
669                            size,
670                            dat,
671                            type,
672                            exp,
673                            psize,
674                            path))
675     {
676       GNUNET_SQ_cleanup_result (rs);
677       break;
678     }
679     GNUNET_SQ_cleanup_result (rs);
680   }
681   GNUNET_SQ_reset (plugin->dbh,
682                    plugin->get_closest_stmt);
683   return cnt;
684 }
685
686
687 /**
688  * Entry point for the plugin.
689  *
690  * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`)
691  * @return the plugin's closure (our `struct Plugin`)
692  */
693 void *
694 libgnunet_plugin_datacache_sqlite_init (void *cls)
695 {
696   struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
697   struct GNUNET_DATACACHE_PluginFunctions *api;
698   struct Plugin *plugin;
699   char *fn;
700   char *fn_utf8;
701   sqlite3 *dbh;
702   char *emsg;
703
704   if (GNUNET_YES ==
705       GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
706                                             "datacache-sqlite",
707                                             "IN_MEMORY"))
708   {
709     if (SQLITE_OK != sqlite3_open (":memory:", &dbh))
710       return NULL;
711     fn_utf8 = NULL;
712   }
713   else
714   {
715     fn = GNUNET_DISK_mktemp ("gnunet-datacache");
716     if (fn == NULL)
717       {
718         GNUNET_break (0);
719         return NULL;
720       }
721     /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
722     fn_utf8 = GNUNET_strdup (fn);
723     if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
724     {
725       GNUNET_free (fn);
726       GNUNET_free (fn_utf8);
727       return NULL;
728     }
729     GNUNET_free (fn);
730   }
731
732   SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
733   SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
734   SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
735   SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
736   SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
737   if (GNUNET_YES ==
738       GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
739                                             "datacache-sqlite",
740                                             "IN_MEMORY"))
741     SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
742
743   SQLITE3_EXEC (dbh,
744                 "CREATE TABLE ds091 ("
745                 "  type INTEGER NOT NULL DEFAULT 0,"
746                 "  expire INTEGER NOT NULL,"
747                 "  key BLOB NOT NULL DEFAULT '',"
748                 "  prox INTEGER NOT NULL,"
749                 "  value BLOB NOT NULL,"
750                 "  path BLOB DEFAULT '')");
751   SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds091 (key,type,expire)");
752   SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds091 (prox,expire)");
753   plugin = GNUNET_new (struct Plugin);
754   plugin->env = env;
755   plugin->dbh = dbh;
756   plugin->fn = fn_utf8;
757
758   if ( (SQLITE_OK !=
759         sq_prepare (plugin->dbh,
760                     "INSERT INTO ds091 (type, expire, key, prox, value, path) "
761                     "VALUES (?, ?, ?, ?, ?, ?)",
762                     &plugin->insert_stmt)) ||
763        (SQLITE_OK !=
764         sq_prepare (plugin->dbh,
765                     "SELECT count(*) FROM ds091 "
766                     "WHERE key=? AND type=? AND expire >= ?",
767                     &plugin->get_count_stmt)) ||
768        (SQLITE_OK !=
769         sq_prepare (plugin->dbh,
770                     "SELECT value,expire,path FROM ds091"
771                     " WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
772                     &plugin->get_stmt)) ||
773        (SQLITE_OK !=
774         sq_prepare (plugin->dbh,
775                     "SELECT _ROWID_,key,value FROM ds091"
776                     " WHERE expire < ?"
777                     " ORDER BY expire ASC LIMIT 1",
778                     &plugin->del_expired_stmt)) ||
779        (SQLITE_OK !=
780         sq_prepare (plugin->dbh,
781                     "SELECT _ROWID_,key,value FROM ds091"
782                     " ORDER BY prox ASC, expire ASC LIMIT 1",
783                     &plugin->del_select_stmt)) ||
784        (SQLITE_OK !=
785         sq_prepare (plugin->dbh,
786                     "DELETE FROM ds091 WHERE _ROWID_=?",
787                     &plugin->del_stmt)) ||
788        (SQLITE_OK !=
789         sq_prepare (plugin->dbh,
790                     "SELECT value,expire,path,key,type FROM ds091 "
791                     "ORDER BY key LIMIT 1 OFFSET ?",
792                     &plugin->get_random_stmt)) ||
793        (SQLITE_OK !=
794         sq_prepare (plugin->dbh,
795                     "SELECT value,expire,path,type,key FROM ds091 "
796                     "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
797                     &plugin->get_closest_stmt))
798        )
799   {
800     LOG_SQLITE (plugin->dbh,
801                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
802                 "sq_prepare");
803     GNUNET_break (SQLITE_OK ==
804                   sqlite3_close (plugin->dbh));
805     GNUNET_free (plugin);
806     return NULL;
807   }
808
809   api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
810   api->cls = plugin;
811   api->get = &sqlite_plugin_get;
812   api->put = &sqlite_plugin_put;
813   api->del = &sqlite_plugin_del;
814   api->get_random = &sqlite_plugin_get_random;
815   api->get_closest = &sqlite_plugin_get_closest;
816   LOG (GNUNET_ERROR_TYPE_INFO,
817        "Sqlite datacache running\n");
818   return api;
819 }
820
821
822 /**
823  * Exit point from the plugin.
824  *
825  * @param cls closure (our `struct Plugin`)
826  * @return NULL
827  */
828 void *
829 libgnunet_plugin_datacache_sqlite_done (void *cls)
830 {
831   struct GNUNET_DATACACHE_PluginFunctions *api = cls;
832   struct Plugin *plugin = api->cls;
833   int result;
834
835 #if SQLITE_VERSION_NUMBER >= 3007000
836   sqlite3_stmt *stmt;
837 #endif
838
839 #if !WINDOWS || defined(__CYGWIN__)
840   if ( (NULL != plugin->fn) &&
841        (0 != UNLINK (plugin->fn)) )
842     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
843                        "unlink",
844                        plugin->fn);
845   GNUNET_free_non_null (plugin->fn);
846 #endif
847   sqlite3_finalize (plugin->insert_stmt);
848   sqlite3_finalize (plugin->get_count_stmt);
849   sqlite3_finalize (plugin->get_stmt);
850   sqlite3_finalize (plugin->del_select_stmt);
851   sqlite3_finalize (plugin->del_expired_stmt);
852   sqlite3_finalize (plugin->del_stmt);
853   sqlite3_finalize (plugin->get_random_stmt);
854   sqlite3_finalize (plugin->get_closest_stmt);
855   result = sqlite3_close (plugin->dbh);
856 #if SQLITE_VERSION_NUMBER >= 3007000
857   if (SQLITE_BUSY == result)
858   {
859     LOG (GNUNET_ERROR_TYPE_WARNING,
860          _("Tried to close sqlite without finalizing all prepared statements.\n"));
861     stmt = sqlite3_next_stmt (plugin->dbh, NULL);
862     while (NULL != stmt)
863     {
864       result = sqlite3_finalize (stmt);
865       if (result != SQLITE_OK)
866         LOG (GNUNET_ERROR_TYPE_WARNING,
867              "Failed to close statement %p: %d\n",
868              stmt,
869              result);
870       stmt = sqlite3_next_stmt (plugin->dbh, NULL);
871     }
872     result = sqlite3_close (plugin->dbh);
873   }
874 #endif
875   if (SQLITE_OK != result)
876     LOG_SQLITE (plugin->dbh,
877                 GNUNET_ERROR_TYPE_ERROR,
878                 "sqlite3_close");
879
880 #if WINDOWS && !defined(__CYGWIN__)
881   if ( (NULL != plugin->fn) &&
882        (0 != UNLINK (plugin->fn)) )
883     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
884                        "unlink",
885                        plugin->fn);
886   GNUNET_free_non_null (plugin->fn);
887 #endif
888   GNUNET_free (plugin);
889   GNUNET_free (api);
890   return NULL;
891 }
892
893
894
895 /* end of plugin_datacache_sqlite.c */