aboutsummaryrefslogtreecommitdiff
path: root/src/peerstore/plugin_peerstore_sqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/peerstore/plugin_peerstore_sqlite.c')
-rw-r--r--src/peerstore/plugin_peerstore_sqlite.c464
1 files changed, 274 insertions, 190 deletions
diff --git a/src/peerstore/plugin_peerstore_sqlite.c b/src/peerstore/plugin_peerstore_sqlite.c
index 2cd7e22cf..440263d44 100644
--- a/src/peerstore/plugin_peerstore_sqlite.c
+++ b/src/peerstore/plugin_peerstore_sqlite.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V. 3 * Copyright (C) 2013, 2017 GNUnet e.V.
4 * 4 *
5 * GNUnet is free software; you can redistribute it and/or modify 5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published 6 * it under the terms of the GNU General Public License as published
@@ -22,11 +22,13 @@
22 * @file peerstore/plugin_peerstore_sqlite.c 22 * @file peerstore/plugin_peerstore_sqlite.c
23 * @brief sqlite-based peerstore backend 23 * @brief sqlite-based peerstore backend
24 * @author Omar Tarabai 24 * @author Omar Tarabai
25 * @author Christian Grothoff
25 */ 26 */
26 27
27#include "platform.h" 28#include "platform.h"
28#include "gnunet_peerstore_plugin.h" 29#include "gnunet_peerstore_plugin.h"
29#include "gnunet_peerstore_service.h" 30#include "gnunet_peerstore_service.h"
31#include "gnunet_sq_lib.h"
30#include "peerstore.h" 32#include "peerstore.h"
31#include <sqlite3.h> 33#include <sqlite3.h>
32 34
@@ -111,6 +113,7 @@ struct Plugin
111 113
112}; 114};
113 115
116
114/** 117/**
115 * Delete records with the given key 118 * Delete records with the given key
116 * 119 *
@@ -118,40 +121,50 @@ struct Plugin
118 * @param sub_system name of sub system 121 * @param sub_system name of sub system
119 * @param peer Peer identity (can be NULL) 122 * @param peer Peer identity (can be NULL)
120 * @param key entry key string (can be NULL) 123 * @param key entry key string (can be NULL)
121 * @return number of deleted records 124 * @return number of deleted records, #GNUNE_SYSERR on error
122 */ 125 */
123static int 126static int
124peerstore_sqlite_delete_records (void *cls, const char *sub_system, 127peerstore_sqlite_delete_records (void *cls,
128 const char *sub_system,
125 const struct GNUNET_PeerIdentity *peer, 129 const struct GNUNET_PeerIdentity *peer,
126 const char *key) 130 const char *key)
127{ 131{
128 struct Plugin *plugin = cls; 132 struct Plugin *plugin = cls;
129 sqlite3_stmt *stmt = plugin->delete_peerstoredata; 133 sqlite3_stmt *stmt = plugin->delete_peerstoredata;
134 struct GNUNET_SQ_QueryParam params[] = {
135 GNUNET_SQ_query_param_string (sub_system),
136 GNUNET_SQ_query_param_auto_from_type (peer),
137 GNUNET_SQ_query_param_string (key),
138 GNUNET_SQ_query_param_end
139 };
140 int ret;
130 141
131 if ((SQLITE_OK != 142 if (GNUNET_OK !=
132 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 143 GNUNET_SQ_bind (stmt,
133 SQLITE_STATIC)) || 144 params))
134 (SQLITE_OK !=
135 sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
136 SQLITE_STATIC)) ||
137 (SQLITE_OK !=
138 sqlite3_bind_text (stmt, 3, key, strlen (key) + 1, SQLITE_STATIC)))
139 { 145 {
140 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 146 LOG_SQLITE (plugin,
147 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
141 "sqlite3_bind"); 148 "sqlite3_bind");
149 GNUNET_SQ_reset (plugin->dbh,
150 stmt);
151 return GNUNET_SYSERR;
142 } 152 }
143 else if (SQLITE_DONE != sqlite3_step (stmt)) 153 if (SQLITE_DONE !=
154 sqlite3_step (stmt))
144 { 155 {
145 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 156 LOG_SQLITE (plugin,
157 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
146 "sqlite3_step"); 158 "sqlite3_step");
159 ret = GNUNET_SYSERR;
147 } 160 }
148 if (SQLITE_OK != sqlite3_reset (stmt)) 161 else
149 { 162 {
150 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 163 ret = sqlite3_changes (plugin->dbh);
151 "sqlite3_reset");
152 return 0;
153 } 164 }
154 return sqlite3_changes (plugin->dbh); 165 GNUNET_SQ_reset (plugin->dbh,
166 stmt);
167 return ret;
155} 168}
156 169
157 170
@@ -172,28 +185,36 @@ peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
172{ 185{
173 struct Plugin *plugin = cls; 186 struct Plugin *plugin = cls;
174 sqlite3_stmt *stmt = plugin->expire_peerstoredata; 187 sqlite3_stmt *stmt = plugin->expire_peerstoredata;
188 struct GNUNET_SQ_QueryParam params[] = {
189 GNUNET_SQ_query_param_absolute_time (&now),
190 GNUNET_SQ_query_param_end
191 };
175 192
176 if (SQLITE_OK != 193 if (GNUNET_OK !=
177 sqlite3_bind_int64 (stmt, 1, (sqlite3_uint64) now.abs_value_us)) 194 GNUNET_SQ_bind (stmt,
195 params))
178 { 196 {
179 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 197 LOG_SQLITE (plugin,
198 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
180 "sqlite3_bind"); 199 "sqlite3_bind");
200 GNUNET_SQ_reset (plugin->dbh,
201 stmt);
202 return GNUNET_SYSERR;
181 } 203 }
182 else if (SQLITE_DONE != sqlite3_step (stmt)) 204 if (SQLITE_DONE != sqlite3_step (stmt))
183 { 205 {
184 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 206 LOG_SQLITE (plugin,
207 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
185 "sqlite3_step"); 208 "sqlite3_step");
186 } 209 GNUNET_SQ_reset (plugin->dbh,
187 if (SQLITE_OK != sqlite3_reset (stmt)) 210 stmt);
188 {
189 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
190 "sqlite3_reset");
191 return GNUNET_SYSERR; 211 return GNUNET_SYSERR;
192 } 212 }
193 if (NULL != cont) 213 if (NULL != cont)
194 { 214 cont (cont_cls,
195 cont (cont_cls, sqlite3_changes (plugin->dbh)); 215 sqlite3_changes (plugin->dbh));
196 } 216 GNUNET_SQ_reset (plugin->dbh,
217 stmt);
197 return GNUNET_OK; 218 return GNUNET_OK;
198} 219}
199 220
@@ -213,7 +234,8 @@ peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
213 * called 234 * called
214 */ 235 */
215static int 236static int
216peerstore_sqlite_iterate_records (void *cls, const char *sub_system, 237peerstore_sqlite_iterate_records (void *cls,
238 const char *sub_system,
217 const struct GNUNET_PeerIdentity *peer, 239 const struct GNUNET_PeerIdentity *peer,
218 const char *key, 240 const char *key,
219 GNUNET_PEERSTORE_Processor iter, 241 GNUNET_PEERSTORE_Processor iter,
@@ -223,94 +245,115 @@ peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
223 sqlite3_stmt *stmt; 245 sqlite3_stmt *stmt;
224 int err = 0; 246 int err = 0;
225 int sret; 247 int sret;
226 struct GNUNET_PEERSTORE_Record *ret; 248 struct GNUNET_PEERSTORE_Record rec;
227 249
228 LOG (GNUNET_ERROR_TYPE_DEBUG, "Executing iterate request on sqlite db.\n"); 250 LOG (GNUNET_ERROR_TYPE_DEBUG,
229 if (NULL == peer && NULL == key) 251 "Executing iterate request on sqlite db.\n");
230 { 252 if (NULL == peer)
231 stmt = plugin->select_peerstoredata;
232 err =
233 (SQLITE_OK !=
234 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
235 SQLITE_STATIC));
236 }
237 else if (NULL == key)
238 {
239 stmt = plugin->select_peerstoredata_by_pid;
240 err =
241 (SQLITE_OK !=
242 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
243 SQLITE_STATIC)) ||
244 (SQLITE_OK !=
245 sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
246 SQLITE_STATIC));
247 }
248 else if (NULL == peer)
249 { 253 {
250 stmt = plugin->select_peerstoredata_by_key; 254 if (NULL == key)
251 err = 255 {
252 (SQLITE_OK != 256 struct GNUNET_SQ_QueryParam params[] = {
253 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 257 GNUNET_SQ_query_param_string (sub_system),
254 SQLITE_STATIC)) || 258 GNUNET_SQ_query_param_end
255 (SQLITE_OK != 259 };
256 sqlite3_bind_text (stmt, 2, key, strlen (key) + 1, SQLITE_STATIC)); 260
261 stmt = plugin->select_peerstoredata;
262 err = GNUNET_SQ_bind (stmt,
263 params);
264 }
265 else
266 {
267 struct GNUNET_SQ_QueryParam params[] = {
268 GNUNET_SQ_query_param_string (sub_system),
269 GNUNET_SQ_query_param_string (key),
270 GNUNET_SQ_query_param_end
271 };
272
273 stmt = plugin->select_peerstoredata_by_key;
274 err = GNUNET_SQ_bind (stmt,
275 params);
276 }
257 } 277 }
258 else 278 else
259 { 279 {
260 stmt = plugin->select_peerstoredata_by_all; 280 if (NULL == key)
261 err = 281 {
262 (SQLITE_OK != 282 struct GNUNET_SQ_QueryParam params[] = {
263 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 283 GNUNET_SQ_query_param_string (sub_system),
264 SQLITE_STATIC)) || 284 GNUNET_SQ_query_param_auto_from_type (peer),
265 (SQLITE_OK != 285 GNUNET_SQ_query_param_end
266 sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity), 286 };
267 SQLITE_STATIC)) || 287
268 (SQLITE_OK != 288 stmt = plugin->select_peerstoredata_by_pid;
269 sqlite3_bind_text (stmt, 3, key, strlen (key) + 1, SQLITE_STATIC)); 289 err = GNUNET_SQ_bind (stmt,
290 params);
291 }
292 else
293 {
294 struct GNUNET_SQ_QueryParam params[] = {
295 GNUNET_SQ_query_param_string (sub_system),
296 GNUNET_SQ_query_param_auto_from_type (peer),
297 GNUNET_SQ_query_param_string (key),
298 GNUNET_SQ_query_param_end
299 };
300
301 stmt = plugin->select_peerstoredata_by_all;
302 err = GNUNET_SQ_bind (stmt,
303 params);
304 }
270 } 305 }
271 306
272 if (err) 307 if (GNUNET_OK != err)
273 { 308 {
274 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 309 LOG_SQLITE (plugin,
310 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
275 "sqlite3_bind_XXXX"); 311 "sqlite3_bind_XXXX");
276 if (SQLITE_OK != sqlite3_reset (stmt)) 312 GNUNET_SQ_reset (plugin->dbh,
277 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 313 stmt);
278 "sqlite3_reset");
279 return GNUNET_SYSERR; 314 return GNUNET_SYSERR;
280 } 315 }
316
317 err = 0;
281 while (SQLITE_ROW == (sret = sqlite3_step (stmt))) 318 while (SQLITE_ROW == (sret = sqlite3_step (stmt)))
282 { 319 {
283 LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning a matched record.\n"); 320 LOG (GNUNET_ERROR_TYPE_DEBUG,
284 ret = GNUNET_new (struct GNUNET_PEERSTORE_Record); 321 "Returning a matched record.\n");
285 322 struct GNUNET_SQ_ResultSpec rs[] = {
286 ret->sub_system = (char *) sqlite3_column_text (stmt, 0); 323 GNUNET_SQ_result_spec_string (&rec.sub_system),
287 ret->peer = (struct GNUNET_PeerIdentity *) sqlite3_column_blob (stmt, 1); 324 GNUNET_SQ_result_spec_auto_from_type (&rec.peer),
288 ret->key = (char *) sqlite3_column_text (stmt, 2); 325 GNUNET_SQ_result_spec_string (&rec.key),
289 ret->value = (void *) sqlite3_column_blob (stmt, 3); 326 GNUNET_SQ_result_spec_variable_size (&rec.value, &rec.value_size),
290 ret->value_size = sqlite3_column_bytes (stmt, 3); 327 GNUNET_SQ_result_spec_absolute_time (&rec.expiry),
291 ret->expiry = GNUNET_new (struct GNUNET_TIME_Absolute); 328 GNUNET_SQ_result_spec_end
292 329 };
293 ret->expiry->abs_value_us = (uint64_t) sqlite3_column_int64 (stmt, 4); 330
331 if (GNUNET_OK !=
332 GNUNET_SQ_extract_result (stmt,
333 rs))
334 {
335 GNUNET_break (0);
336 break;
337 }
294 if (NULL != iter) 338 if (NULL != iter)
295 iter (iter_cls, ret, NULL); 339 iter (iter_cls,
296 GNUNET_free (ret->expiry); 340 &rec,
297 GNUNET_free (ret); 341 NULL);
342 GNUNET_SQ_cleanup_result (rs);
298 } 343 }
299 if (SQLITE_DONE != sret) 344 if (SQLITE_DONE != sret)
300 { 345 {
301 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step"); 346 LOG_SQLITE (plugin,
302 err = 1; 347 GNUNET_ERROR_TYPE_ERROR,
303 } 348 "sqlite_step");
304 if (SQLITE_OK != sqlite3_reset (stmt))
305 {
306 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
307 "sqlite3_reset");
308 err = 1; 349 err = 1;
309 } 350 }
351 GNUNET_SQ_reset (plugin->dbh,
352 stmt);
310 if (NULL != iter) 353 if (NULL != iter)
311 { 354 iter (iter_cls,
312 iter (iter_cls, NULL, err ? "sqlite error" : NULL); 355 NULL,
313 } 356 err ? "sqlite error" : NULL);
314 return GNUNET_OK; 357 return GNUNET_OK;
315} 358}
316 359
@@ -333,9 +376,12 @@ peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
333 * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called 376 * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called
334 */ 377 */
335static int 378static int
336peerstore_sqlite_store_record (void *cls, const char *sub_system, 379peerstore_sqlite_store_record (void *cls,
380 const char *sub_system,
337 const struct GNUNET_PeerIdentity *peer, 381 const struct GNUNET_PeerIdentity *peer,
338 const char *key, const void *value, size_t size, 382 const char *key,
383 const void *value,
384 size_t size,
339 struct GNUNET_TIME_Absolute expiry, 385 struct GNUNET_TIME_Absolute expiry,
340 enum GNUNET_PEERSTORE_StoreOption options, 386 enum GNUNET_PEERSTORE_StoreOption options,
341 GNUNET_PEERSTORE_Continuation cont, 387 GNUNET_PEERSTORE_Continuation cont,
@@ -343,39 +389,39 @@ peerstore_sqlite_store_record (void *cls, const char *sub_system,
343{ 389{
344 struct Plugin *plugin = cls; 390 struct Plugin *plugin = cls;
345 sqlite3_stmt *stmt = plugin->insert_peerstoredata; 391 sqlite3_stmt *stmt = plugin->insert_peerstoredata;
392 struct GNUNET_SQ_QueryParam params[] = {
393 GNUNET_SQ_query_param_string (sub_system),
394 GNUNET_SQ_query_param_auto_from_type (peer),
395 GNUNET_SQ_query_param_string (key),
396 GNUNET_SQ_query_param_fixed_size (value, size),
397 GNUNET_SQ_query_param_absolute_time (&expiry),
398 GNUNET_SQ_query_param_end
399 };
346 400
347 if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options) 401 if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
348 { 402 {
349 peerstore_sqlite_delete_records (cls, sub_system, peer, key); 403 peerstore_sqlite_delete_records (cls,
404 sub_system,
405 peer,
406 key);
350 } 407 }
351 if (SQLITE_OK != 408 if (GNUNET_OK !=
352 sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1, 409 GNUNET_SQ_bind (stmt,
353 SQLITE_STATIC) || 410 params))
354 SQLITE_OK != sqlite3_bind_blob (stmt, 2, peer, 411 LOG_SQLITE (plugin,
355 sizeof (struct GNUNET_PeerIdentity), 412 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
356 SQLITE_STATIC) ||
357 SQLITE_OK != sqlite3_bind_text (stmt, 3, key, strlen (key) + 1,
358 SQLITE_STATIC) ||
359 SQLITE_OK != sqlite3_bind_blob (stmt, 4, value, size, SQLITE_STATIC) ||
360 SQLITE_OK != sqlite3_bind_int64 (stmt, 5,
361 (sqlite3_uint64) expiry.abs_value_us))
362 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
363 "sqlite3_bind"); 413 "sqlite3_bind");
364 else if (SQLITE_DONE != sqlite3_step (stmt)) 414 else if (SQLITE_DONE != sqlite3_step (stmt))
365 { 415 {
366 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 416 LOG_SQLITE (plugin,
417 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
367 "sqlite3_step"); 418 "sqlite3_step");
368 } 419 }
369 if (SQLITE_OK != sqlite3_reset (stmt)) 420 GNUNET_SQ_reset (plugin->dbh,
370 { 421 stmt);
371 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
372 "sqlite3_reset");
373 return GNUNET_SYSERR;
374 }
375 if (NULL != cont) 422 if (NULL != cont)
376 { 423 cont (cont_cls,
377 cont (cont_cls, GNUNET_OK); 424 GNUNET_OK);
378 }
379 return GNUNET_OK; 425 return GNUNET_OK;
380} 426}
381 427
@@ -388,15 +434,25 @@ peerstore_sqlite_store_record (void *cls, const char *sub_system,
388 * @return 0 on success 434 * @return 0 on success
389 */ 435 */
390static int 436static int
391sql_exec (sqlite3 * dbh, const char *sql) 437sql_exec (sqlite3 *dbh,
438 const char *sql)
392{ 439{
393 int result; 440 int result;
394 441
395 result = sqlite3_exec (dbh, sql, NULL, NULL, NULL); 442 result = sqlite3_exec (dbh,
396 LOG (GNUNET_ERROR_TYPE_DEBUG, "Executed `%s' / %d\n", sql, result); 443 sql,
397 if (result != SQLITE_OK) 444 NULL,
398 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error executing SQL query: %s\n %s\n"), 445 NULL,
399 sqlite3_errmsg (dbh), sql); 446 NULL);
447 LOG (GNUNET_ERROR_TYPE_DEBUG,
448 "Executed `%s' / %d\n",
449 sql,
450 result);
451 if (SQLITE_OK != result)
452 LOG (GNUNET_ERROR_TYPE_ERROR,
453 _("Error executing SQL query: %s\n %s\n"),
454 sqlite3_errmsg (dbh),
455 sql);
400 return result; 456 return result;
401} 457}
402 458
@@ -410,38 +466,33 @@ sql_exec (sqlite3 * dbh, const char *sql)
410 * @return 0 on success 466 * @return 0 on success
411 */ 467 */
412static int 468static int
413sql_prepare (sqlite3 * dbh, const char *sql, sqlite3_stmt ** stmt) 469sql_prepare (sqlite3 *dbh,
470 const char *sql,
471 sqlite3_stmt ** stmt)
414{ 472{
415 char *tail; 473 char *tail;
416 int result; 474 int result;
417 475
418 result = 476 result = sqlite3_prepare_v2 (dbh,
419 sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt, (const char **) &tail); 477 sql,
420 LOG (GNUNET_ERROR_TYPE_DEBUG, "Prepared `%s' / %p: %d\n", sql, *stmt, result); 478 strlen (sql),
421 if (result != SQLITE_OK) 479 stmt,
422 LOG (GNUNET_ERROR_TYPE_ERROR, _("Error preparing SQL query: %s\n %s\n"), 480 (const char **) &tail);
423 sqlite3_errmsg (dbh), sql); 481 LOG (GNUNET_ERROR_TYPE_DEBUG,
482 "Prepared `%s' / %p: %d\n",
483 sql,
484 *stmt,
485 result);
486 if (SQLITE_OK != result)
487 LOG (GNUNET_ERROR_TYPE_ERROR,
488 _("Error preparing SQL query: %s\n %s\n"),
489 sqlite3_errmsg (dbh),
490 sql);
424 return result; 491 return result;
425} 492}
426 493
427 494
428/** 495/**
429 * sqlite3 custom function for comparison of uint64_t values
430 * since it is not supported by default
431 */
432void
433sqlite3_lessthan (sqlite3_context * ctx, int dummy, sqlite3_value ** values)
434{
435 uint64_t v1;
436 uint64_t v2;
437
438 v1 = (uint64_t) sqlite3_value_int64 (values[0]);
439 v2 = (uint64_t) sqlite3_value_int64 (values[1]);
440 sqlite3_result_int (ctx, v1 < v2);
441}
442
443
444/**
445 * Initialize the database connections and associated 496 * Initialize the database connections and associated
446 * data structures (create tables and indices 497 * data structures (create tables and indices
447 * as needed as well). 498 * as needed as well).
@@ -455,10 +506,13 @@ database_setup (struct Plugin *plugin)
455 char *filename; 506 char *filename;
456 507
457 if (GNUNET_OK != 508 if (GNUNET_OK !=
458 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "peerstore-sqlite", 509 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
459 "FILENAME", &filename)) 510 "peerstore-sqlite",
511 "FILENAME",
512 &filename))
460 { 513 {
461 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "peerstore-sqlite", 514 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
515 "peerstore-sqlite",
462 "FILENAME"); 516 "FILENAME");
463 return GNUNET_SYSERR; 517 return GNUNET_SYSERR;
464 } 518 }
@@ -474,60 +528,81 @@ database_setup (struct Plugin *plugin)
474 /* filename should be UTF-8-encoded. If it isn't, it's a bug */ 528 /* filename should be UTF-8-encoded. If it isn't, it's a bug */
475 plugin->fn = filename; 529 plugin->fn = filename;
476 /* Open database and precompile statements */ 530 /* Open database and precompile statements */
477 if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh)) 531 if (SQLITE_OK != sqlite3_open (plugin->fn,
532 &plugin->dbh))
478 { 533 {
479 LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize SQLite: %s.\n"), 534 LOG (GNUNET_ERROR_TYPE_ERROR,
535 _("Unable to initialize SQLite: %s.\n"),
480 sqlite3_errmsg (plugin->dbh)); 536 sqlite3_errmsg (plugin->dbh));
481 return GNUNET_SYSERR; 537 return GNUNET_SYSERR;
482 } 538 }
483 sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY"); 539 sql_exec (plugin->dbh,
484 sql_exec (plugin->dbh, "PRAGMA synchronous=OFF"); 540 "PRAGMA temp_store=MEMORY");
485 sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF"); 541 sql_exec (plugin->dbh,
486 sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL"); 542 "PRAGMA synchronous=OFF");
487 sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\""); 543 sql_exec (plugin->dbh,
488 sql_exec (plugin->dbh, "PRAGMA page_size=4096"); 544 "PRAGMA legacy_file_format=OFF");
489 sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS); 545 sql_exec (plugin->dbh,
546 "PRAGMA auto_vacuum=INCREMENTAL");
547 sql_exec (plugin->dbh,
548 "PRAGMA encoding=\"UTF-8\"");
549 sql_exec (plugin->dbh,
550 "PRAGMA page_size=4096");
551 sqlite3_busy_timeout (plugin->dbh,
552 BUSY_TIMEOUT_MS);
490 /* Create tables */ 553 /* Create tables */
491 sql_exec (plugin->dbh, 554 sql_exec (plugin->dbh,
492 "CREATE TABLE IF NOT EXISTS peerstoredata (\n" 555 "CREATE TABLE IF NOT EXISTS peerstoredata (\n"
493 " sub_system TEXT NOT NULL,\n" " peer_id BLOB NOT NULL,\n" 556 " sub_system TEXT NOT NULL,\n"
494 " key TEXT NOT NULL,\n" " value BLOB NULL,\n" 557 " peer_id BLOB NOT NULL,\n"
495 " expiry sqlite3_uint64 NOT NULL" ");"); 558 " key TEXT NOT NULL,\n"
496 sqlite3_create_function (plugin->dbh, "UINT64_LT", 2, SQLITE_UTF8, NULL, 559 " value BLOB NULL,\n"
497 &sqlite3_lessthan, NULL, NULL); 560 " expiry INT8 NOT NULL" ");");
498 /* Create Indices */ 561 /* Create Indices */
499 if (SQLITE_OK != 562 if (SQLITE_OK !=
500 sqlite3_exec (plugin->dbh, 563 sqlite3_exec (plugin->dbh,
501 "CREATE INDEX IF NOT EXISTS peerstoredata_key_index ON peerstoredata (sub_system, peer_id, key)", 564 "CREATE INDEX IF NOT EXISTS peerstoredata_key_index ON peerstoredata (sub_system, peer_id, key)",
502 NULL, NULL, NULL)) 565 NULL,
566 NULL,
567 NULL))
503 { 568 {
504 LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to create indices: %s.\n"), 569 LOG (GNUNET_ERROR_TYPE_ERROR,
570 _("Unable to create indices: %s.\n"),
505 sqlite3_errmsg (plugin->dbh)); 571 sqlite3_errmsg (plugin->dbh));
506 return GNUNET_SYSERR; 572 return GNUNET_SYSERR;
507 } 573 }
508 /* Prepare statements */ 574 /* Prepare statements */
509 575
510 sql_prepare (plugin->dbh, 576 sql_prepare (plugin->dbh,
511 "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry) VALUES (?,?,?,?,?);", 577 "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry)"
578 " VALUES (?,?,?,?,?);",
512 &plugin->insert_peerstoredata); 579 &plugin->insert_peerstoredata);
513 sql_prepare (plugin->dbh, 580 sql_prepare (plugin->dbh,
514 "SELECT * FROM peerstoredata" " WHERE sub_system = ?", 581 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
582 " WHERE sub_system = ?",
515 &plugin->select_peerstoredata); 583 &plugin->select_peerstoredata);
516 sql_prepare (plugin->dbh, 584 sql_prepare (plugin->dbh,
517 "SELECT * FROM peerstoredata" " WHERE sub_system = ?" 585 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
518 " AND peer_id = ?", &plugin->select_peerstoredata_by_pid); 586 " WHERE sub_system = ?"
587 " AND peer_id = ?",
588 &plugin->select_peerstoredata_by_pid);
519 sql_prepare (plugin->dbh, 589 sql_prepare (plugin->dbh,
520 "SELECT * FROM peerstoredata" " WHERE sub_system = ?" 590 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
521 " AND key = ?", &plugin->select_peerstoredata_by_key); 591 " WHERE sub_system = ?"
592 " AND key = ?",
593 &plugin->select_peerstoredata_by_key);
522 sql_prepare (plugin->dbh, 594 sql_prepare (plugin->dbh,
523 "SELECT * FROM peerstoredata" " WHERE sub_system = ?" 595 "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
596 " WHERE sub_system = ?"
524 " AND peer_id = ?" " AND key = ?", 597 " AND peer_id = ?" " AND key = ?",
525 &plugin->select_peerstoredata_by_all); 598 &plugin->select_peerstoredata_by_all);
526 sql_prepare (plugin->dbh, 599 sql_prepare (plugin->dbh,
527 "DELETE FROM peerstoredata" " WHERE UINT64_LT(expiry, ?)", 600 "DELETE FROM peerstoredata"
601 " WHERE expiry < ?",
528 &plugin->expire_peerstoredata); 602 &plugin->expire_peerstoredata);
529 sql_prepare (plugin->dbh, 603 sql_prepare (plugin->dbh,
530 "DELETE FROM peerstoredata" " WHERE sub_system = ?" 604 "DELETE FROM peerstoredata"
605 " WHERE sub_system = ?"
531 " AND peer_id = ?" " AND key = ?", 606 " AND peer_id = ?" " AND key = ?",
532 &plugin->delete_peerstoredata); 607 &plugin->delete_peerstoredata);
533 return GNUNET_OK; 608 return GNUNET_OK;
@@ -545,15 +620,20 @@ database_shutdown (struct Plugin *plugin)
545 int result; 620 int result;
546 sqlite3_stmt *stmt; 621 sqlite3_stmt *stmt;
547 622
548 while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL))) 623 while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh,
624 NULL)))
549 { 625 {
550 result = sqlite3_finalize (stmt); 626 result = sqlite3_finalize (stmt);
551 if (SQLITE_OK != result) 627 if (SQLITE_OK != result)
552 LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to close statement %p: %d\n", 628 LOG (GNUNET_ERROR_TYPE_WARNING,
553 stmt, result); 629 "Failed to close statement %p: %d\n",
630 stmt,
631 result);
554 } 632 }
555 if (SQLITE_OK != sqlite3_close (plugin->dbh)) 633 if (SQLITE_OK != sqlite3_close (plugin->dbh))
556 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); 634 LOG_SQLITE (plugin,
635 GNUNET_ERROR_TYPE_ERROR,
636 "sqlite3_close");
557 GNUNET_free_non_null (plugin->fn); 637 GNUNET_free_non_null (plugin->fn);
558} 638}
559 639
@@ -573,7 +653,9 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
573 653
574 if (NULL != plugin.cfg) 654 if (NULL != plugin.cfg)
575 return NULL; /* can only initialize once! */ 655 return NULL; /* can only initialize once! */
576 memset (&plugin, 0, sizeof (struct Plugin)); 656 memset (&plugin,
657 0,
658 sizeof (struct Plugin));
577 plugin.cfg = cfg; 659 plugin.cfg = cfg;
578 if (GNUNET_OK != database_setup (&plugin)) 660 if (GNUNET_OK != database_setup (&plugin))
579 { 661 {
@@ -585,7 +667,8 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
585 api->store_record = &peerstore_sqlite_store_record; 667 api->store_record = &peerstore_sqlite_store_record;
586 api->iterate_records = &peerstore_sqlite_iterate_records; 668 api->iterate_records = &peerstore_sqlite_iterate_records;
587 api->expire_records = &peerstore_sqlite_expire_records; 669 api->expire_records = &peerstore_sqlite_expire_records;
588 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is running\n"); 670 LOG (GNUNET_ERROR_TYPE_DEBUG,
671 "Sqlite plugin is running\n");
589 return api; 672 return api;
590} 673}
591 674
@@ -605,7 +688,8 @@ libgnunet_plugin_peerstore_sqlite_done (void *cls)
605 database_shutdown (plugin); 688 database_shutdown (plugin);
606 plugin->cfg = NULL; 689 plugin->cfg = NULL;
607 GNUNET_free (api); 690 GNUNET_free (api);
608 LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is finished\n"); 691 LOG (GNUNET_ERROR_TYPE_DEBUG,
692 "Sqlite plugin is finished\n");
609 return NULL; 693 return NULL;
610} 694}
611 695