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