diff options
Diffstat (limited to 'src/peerstore/plugin_peerstore_sqlite.c')
-rw-r--r-- | src/peerstore/plugin_peerstore_sqlite.c | 464 |
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 | */ |
123 | static int | 126 | static int |
124 | peerstore_sqlite_delete_records (void *cls, const char *sub_system, | 127 | peerstore_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 | */ |
215 | static int | 236 | static int |
216 | peerstore_sqlite_iterate_records (void *cls, const char *sub_system, | 237 | peerstore_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 | */ |
335 | static int | 378 | static int |
336 | peerstore_sqlite_store_record (void *cls, const char *sub_system, | 379 | peerstore_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 | */ |
390 | static int | 436 | static int |
391 | sql_exec (sqlite3 * dbh, const char *sql) | 437 | sql_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 | */ |
412 | static int | 468 | static int |
413 | sql_prepare (sqlite3 * dbh, const char *sql, sqlite3_stmt ** stmt) | 469 | sql_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 | */ | ||
432 | void | ||
433 | sqlite3_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 | ||