diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-04-30 07:56:00 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-04-30 07:56:00 +0000 |
commit | 786745c969589eae2aa069885b40eba0f3989507 (patch) | |
tree | 6f5c8573b021ba628b4f135f3fb964728b3e1724 /src/datacache | |
parent | a49b0f351926cf4376a58937a94e37426e3ae167 (diff) | |
download | gnunet-786745c969589eae2aa069885b40eba0f3989507.tar.gz gnunet-786745c969589eae2aa069885b40eba0f3989507.zip |
implementing 'get_closest' API for sqlite and postgres datacache plugins
Diffstat (limited to 'src/datacache')
-rw-r--r-- | src/datacache/datacache.c | 35 | ||||
-rw-r--r-- | src/datacache/plugin_datacache_heap.c | 26 | ||||
-rw-r--r-- | src/datacache/plugin_datacache_postgres.c | 137 | ||||
-rw-r--r-- | src/datacache/plugin_datacache_sqlite.c | 115 |
4 files changed, 309 insertions, 4 deletions
diff --git a/src/datacache/datacache.c b/src/datacache/datacache.c index 426841bc8..6c8d2b8cc 100644 --- a/src/datacache/datacache.c +++ b/src/datacache/datacache.c | |||
@@ -375,4 +375,39 @@ GNUNET_DATACACHE_get_random (struct GNUNET_DATACACHE_Handle *h, | |||
375 | } | 375 | } |
376 | 376 | ||
377 | 377 | ||
378 | /** | ||
379 | * Iterate over the results that are "close" to a particular key in | ||
380 | * the datacache. "close" is defined as numerically larger than @a | ||
381 | * key (when interpreted as a circular address space), with small | ||
382 | * distance. | ||
383 | * | ||
384 | * @param h handle to the datacache | ||
385 | * @param key area of the keyspace to look into | ||
386 | * @param num_results number of results that should be returned to @a iter | ||
387 | * @param iter maybe NULL (to just count) | ||
388 | * @param iter_cls closure for @a iter | ||
389 | * @return the number of results found | ||
390 | */ | ||
391 | unsigned int | ||
392 | GNUNET_DATACACHE_get_closest (struct GNUNET_DATACACHE_Handle *h, | ||
393 | const struct GNUNET_HashCode *key, | ||
394 | unsigned int num_results, | ||
395 | GNUNET_DATACACHE_Iterator iter, | ||
396 | void *iter_cls) | ||
397 | { | ||
398 | GNUNET_STATISTICS_update (h->stats, | ||
399 | gettext_noop ("# proximity search requests received"), | ||
400 | 1, | ||
401 | GNUNET_NO); | ||
402 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
403 | "Processing proximity search at `%s'\n", | ||
404 | GNUNET_h2s (key)); | ||
405 | return h->api->get_closest (h->api->cls, | ||
406 | key, | ||
407 | num_results, | ||
408 | iter, | ||
409 | iter_cls); | ||
410 | } | ||
411 | |||
412 | |||
378 | /* end of datacache.c */ | 413 | /* end of datacache.c */ |
diff --git a/src/datacache/plugin_datacache_heap.c b/src/datacache/plugin_datacache_heap.c index 32e762e23..5492a8ec5 100644 --- a/src/datacache/plugin_datacache_heap.c +++ b/src/datacache/plugin_datacache_heap.c | |||
@@ -413,6 +413,31 @@ heap_plugin_get_random (void *cls, | |||
413 | 413 | ||
414 | 414 | ||
415 | /** | 415 | /** |
416 | * Iterate over the results that are "close" to a particular key in | ||
417 | * the datacache. "close" is defined as numerically larger than @a | ||
418 | * key (when interpreted as a circular address space), with small | ||
419 | * distance. | ||
420 | * | ||
421 | * @param cls closure (internal context for the plugin) | ||
422 | * @param key area of the keyspace to look into | ||
423 | * @param num_results number of results that should be returned to @a iter | ||
424 | * @param iter maybe NULL (to just count) | ||
425 | * @param iter_cls closure for @a iter | ||
426 | * @return the number of results found | ||
427 | */ | ||
428 | static unsigned int | ||
429 | heap_plugin_get_closest (void *cls, | ||
430 | const struct GNUNET_HashCode *key, | ||
431 | unsigned int num_results, | ||
432 | GNUNET_DATACACHE_Iterator iter, | ||
433 | void *iter_cls) | ||
434 | { | ||
435 | GNUNET_break (0); // not implemented! | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
416 | * Entry point for the plugin. | 441 | * Entry point for the plugin. |
417 | * | 442 | * |
418 | * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`) | 443 | * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`) |
@@ -436,6 +461,7 @@ libgnunet_plugin_datacache_heap_init (void *cls) | |||
436 | api->put = &heap_plugin_put; | 461 | api->put = &heap_plugin_put; |
437 | api->del = &heap_plugin_del; | 462 | api->del = &heap_plugin_del; |
438 | api->get_random = &heap_plugin_get_random; | 463 | api->get_random = &heap_plugin_get_random; |
464 | api->get_closest = &heap_plugin_get_closest; | ||
439 | LOG (GNUNET_ERROR_TYPE_INFO, | 465 | LOG (GNUNET_ERROR_TYPE_INFO, |
440 | _("Heap datacache running\n")); | 466 | _("Heap datacache running\n")); |
441 | return api; | 467 | return api; |
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c index 13f944d7c..1156d214e 100644 --- a/src/datacache/plugin_datacache_postgres.c +++ b/src/datacache/plugin_datacache_postgres.c | |||
@@ -163,6 +163,11 @@ init_connection (struct Plugin *plugin) | |||
163 | "ORDER BY key ASC LIMIT 1 OFFSET $1", 1)) || | 163 | "ORDER BY key ASC LIMIT 1 OFFSET $1", 1)) || |
164 | (GNUNET_OK != | 164 | (GNUNET_OK != |
165 | GNUNET_POSTGRES_prepare (plugin->dbh, | 165 | GNUNET_POSTGRES_prepare (plugin->dbh, |
166 | "get_closest", | ||
167 | "SELECT discard_time,type,value,path,key FROM gn090dc " | ||
168 | "WHERE key>=$1 ORDER BY key ASC LIMIT $2", 1)) || | ||
169 | (GNUNET_OK != | ||
170 | GNUNET_POSTGRES_prepare (plugin->dbh, | ||
166 | "delrow", | 171 | "delrow", |
167 | "DELETE FROM gn090dc WHERE oid=$1", 1)) || | 172 | "DELETE FROM gn090dc WHERE oid=$1", 1)) || |
168 | (GNUNET_OK != | 173 | (GNUNET_OK != |
@@ -259,11 +264,11 @@ postgres_plugin_get (void *cls, | |||
259 | 264 | ||
260 | const char *paramValues[] = { | 265 | const char *paramValues[] = { |
261 | (const char *) key, | 266 | (const char *) key, |
262 | (const char *) &btype, | 267 | (const char *) &btype |
263 | }; | 268 | }; |
264 | int paramLengths[] = { | 269 | int paramLengths[] = { |
265 | sizeof (struct GNUNET_HashCode), | 270 | sizeof (struct GNUNET_HashCode), |
266 | sizeof (btype), | 271 | sizeof (btype) |
267 | }; | 272 | }; |
268 | const int paramFormats[] = { 1, 1 }; | 273 | const int paramFormats[] = { 1, 1 }; |
269 | struct GNUNET_TIME_Absolute expiration_time; | 274 | struct GNUNET_TIME_Absolute expiration_time; |
@@ -433,10 +438,10 @@ postgres_plugin_get_random (void *cls, | |||
433 | unsigned int type; | 438 | unsigned int type; |
434 | PGresult *res; | 439 | PGresult *res; |
435 | const char *paramValues[] = { | 440 | const char *paramValues[] = { |
436 | (const char *) &off_be, | 441 | (const char *) &off_be |
437 | }; | 442 | }; |
438 | int paramLengths[] = { | 443 | int paramLengths[] = { |
439 | sizeof (off_be), | 444 | sizeof (off_be) |
440 | }; | 445 | }; |
441 | const int paramFormats[] = { 1 }; | 446 | const int paramFormats[] = { 1 }; |
442 | 447 | ||
@@ -507,6 +512,129 @@ postgres_plugin_get_random (void *cls, | |||
507 | 512 | ||
508 | 513 | ||
509 | /** | 514 | /** |
515 | * Iterate over the results that are "close" to a particular key in | ||
516 | * the datacache. "close" is defined as numerically larger than @a | ||
517 | * key (when interpreted as a circular address space), with small | ||
518 | * distance. | ||
519 | * | ||
520 | * @param cls closure (internal context for the plugin) | ||
521 | * @param key area of the keyspace to look into | ||
522 | * @param num_results number of results that should be returned to @a iter | ||
523 | * @param iter maybe NULL (to just count) | ||
524 | * @param iter_cls closure for @a iter | ||
525 | * @return the number of results found | ||
526 | */ | ||
527 | static unsigned int | ||
528 | postgres_plugin_get_closest (void *cls, | ||
529 | const struct GNUNET_HashCode *key, | ||
530 | unsigned int num_results, | ||
531 | GNUNET_DATACACHE_Iterator iter, | ||
532 | void *iter_cls) | ||
533 | { | ||
534 | struct Plugin *plugin = cls; | ||
535 | uint32_t nbo_limit = htonl (num_results); | ||
536 | const char *paramValues[] = { | ||
537 | (const char *) key, | ||
538 | (const char *) &nbo_limit, | ||
539 | }; | ||
540 | int paramLengths[] = { | ||
541 | sizeof (struct GNUNET_HashCode), | ||
542 | sizeof (nbo_limit) | ||
543 | |||
544 | }; | ||
545 | const int paramFormats[] = { 1, 1 }; | ||
546 | struct GNUNET_TIME_Absolute expiration_time; | ||
547 | uint32_t size; | ||
548 | unsigned int type; | ||
549 | unsigned int cnt; | ||
550 | unsigned int i; | ||
551 | unsigned int path_len; | ||
552 | const struct GNUNET_PeerIdentity *path; | ||
553 | PGresult *res; | ||
554 | |||
555 | res = | ||
556 | PQexecPrepared (plugin->dbh, | ||
557 | "get_closest", | ||
558 | 2, | ||
559 | paramValues, | ||
560 | paramLengths, | ||
561 | paramFormats, | ||
562 | 1); | ||
563 | if (GNUNET_OK != | ||
564 | GNUNET_POSTGRES_check_result (plugin->dbh, | ||
565 | res, | ||
566 | PGRES_TUPLES_OK, | ||
567 | "PQexecPrepared", | ||
568 | "get_closest")) | ||
569 | { | ||
570 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
571 | "Ending iteration (postgres error)\n"); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | if (0 == (cnt = PQntuples (res))) | ||
576 | { | ||
577 | /* no result */ | ||
578 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
579 | "Ending iteration (no more results)\n"); | ||
580 | PQclear (res); | ||
581 | return 0; | ||
582 | } | ||
583 | if (NULL == iter) | ||
584 | { | ||
585 | PQclear (res); | ||
586 | return cnt; | ||
587 | } | ||
588 | if ( (5 != PQnfields (res)) || | ||
589 | (sizeof (uint64_t) != PQfsize (res, 0)) || | ||
590 | (sizeof (uint32_t) != PQfsize (res, 1)) || | ||
591 | (sizeof (struct GNUNET_HashCode) != PQfsize (res, 4)) ) | ||
592 | { | ||
593 | GNUNET_break (0); | ||
594 | PQclear (res); | ||
595 | return 0; | ||
596 | } | ||
597 | for (i = 0; i < cnt; i++) | ||
598 | { | ||
599 | expiration_time.abs_value_us = | ||
600 | GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0)); | ||
601 | type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1)); | ||
602 | size = PQgetlength (res, i, 2); | ||
603 | path_len = PQgetlength (res, i, 3); | ||
604 | if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity))) | ||
605 | { | ||
606 | GNUNET_break (0); | ||
607 | path_len = 0; | ||
608 | } | ||
609 | path_len %= sizeof (struct GNUNET_PeerIdentity); | ||
610 | path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, i, 3); | ||
611 | key = (const struct GNUNET_HashCode *) PQgetvalue (res, i, 4); | ||
612 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
613 | "Found result of size %u bytes and type %u in database\n", | ||
614 | (unsigned int) size, | ||
615 | (unsigned int) type); | ||
616 | if (GNUNET_SYSERR == | ||
617 | iter (iter_cls, | ||
618 | key, | ||
619 | size, | ||
620 | PQgetvalue (res, i, 2), | ||
621 | (enum GNUNET_BLOCK_Type) type, | ||
622 | expiration_time, | ||
623 | path_len, | ||
624 | path)) | ||
625 | { | ||
626 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
627 | "Ending iteration (client error)\n"); | ||
628 | PQclear (res); | ||
629 | return cnt; | ||
630 | } | ||
631 | } | ||
632 | PQclear (res); | ||
633 | return cnt; | ||
634 | } | ||
635 | |||
636 | |||
637 | /** | ||
510 | * Entry point for the plugin. | 638 | * Entry point for the plugin. |
511 | * | 639 | * |
512 | * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`) | 640 | * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`) |
@@ -534,6 +662,7 @@ libgnunet_plugin_datacache_postgres_init (void *cls) | |||
534 | api->put = &postgres_plugin_put; | 662 | api->put = &postgres_plugin_put; |
535 | api->del = &postgres_plugin_del; | 663 | api->del = &postgres_plugin_del; |
536 | api->get_random = &postgres_plugin_get_random; | 664 | api->get_random = &postgres_plugin_get_random; |
665 | api->get_closest = &postgres_plugin_get_closest; | ||
537 | LOG (GNUNET_ERROR_TYPE_INFO, | 666 | LOG (GNUNET_ERROR_TYPE_INFO, |
538 | "Postgres datacache running\n"); | 667 | "Postgres datacache running\n"); |
539 | return api; | 668 | return api; |
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c index d28233772..8dd38a3ac 100644 --- a/src/datacache/plugin_datacache_sqlite.c +++ b/src/datacache/plugin_datacache_sqlite.c | |||
@@ -522,6 +522,120 @@ sqlite_plugin_get_random (void *cls, | |||
522 | 522 | ||
523 | 523 | ||
524 | /** | 524 | /** |
525 | * Iterate over the results that are "close" to a particular key in | ||
526 | * the datacache. "close" is defined as numerically larger than @a | ||
527 | * key (when interpreted as a circular address space), with small | ||
528 | * distance. | ||
529 | * | ||
530 | * @param cls closure (internal context for the plugin) | ||
531 | * @param key area of the keyspace to look into | ||
532 | * @param num_results number of results that should be returned to @a iter | ||
533 | * @param iter maybe NULL (to just count) | ||
534 | * @param iter_cls closure for @a iter | ||
535 | * @return the number of results found | ||
536 | */ | ||
537 | static unsigned int | ||
538 | sqlite_plugin_get_closest (void *cls, | ||
539 | const struct GNUNET_HashCode *key, | ||
540 | unsigned int num_results, | ||
541 | GNUNET_DATACACHE_Iterator iter, | ||
542 | void *iter_cls) | ||
543 | { | ||
544 | struct Plugin *plugin = cls; | ||
545 | sqlite3_stmt *stmt; | ||
546 | struct GNUNET_TIME_Absolute now; | ||
547 | struct GNUNET_TIME_Absolute exp; | ||
548 | unsigned int size; | ||
549 | const char *dat; | ||
550 | unsigned int cnt; | ||
551 | unsigned int psize; | ||
552 | unsigned int type; | ||
553 | int64_t ntime; | ||
554 | const struct GNUNET_PeerIdentity *path; | ||
555 | |||
556 | now = GNUNET_TIME_absolute_get (); | ||
557 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
558 | "Processing GET_CLOSEST for key `%4s'\n", | ||
559 | GNUNET_h2s (key)); | ||
560 | if (SQLITE_OK != | ||
561 | sq_prepare (plugin->dbh, | ||
562 | "SELECT value,expire,path,type,key FROM ds090 WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?", | ||
563 | &stmt)) | ||
564 | { | ||
565 | LOG_SQLITE (plugin->dbh, | ||
566 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
567 | "sq_prepare"); | ||
568 | return 0; | ||
569 | } | ||
570 | ntime = (int64_t) now.abs_value_us; | ||
571 | GNUNET_assert (ntime >= 0); | ||
572 | if ((SQLITE_OK != | ||
573 | sqlite3_bind_blob (stmt, | ||
574 | 1, | ||
575 | key, | ||
576 | sizeof (struct GNUNET_HashCode), | ||
577 | SQLITE_TRANSIENT)) || | ||
578 | (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, now.abs_value_us)) || | ||
579 | (SQLITE_OK != sqlite3_bind_int (stmt, 3, num_results)) ) | ||
580 | { | ||
581 | LOG_SQLITE (plugin->dbh, | ||
582 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
583 | "sqlite3_bind_xxx"); | ||
584 | sqlite3_finalize (stmt); | ||
585 | return 0; | ||
586 | } | ||
587 | cnt = 0; | ||
588 | while (SQLITE_ROW == sqlite3_step (stmt)) | ||
589 | { | ||
590 | if (sizeof (struct GNUNET_HashCode) != | ||
591 | sqlite3_column_bytes (stmt, 4)) | ||
592 | { | ||
593 | GNUNET_break (0); | ||
594 | break; | ||
595 | } | ||
596 | size = sqlite3_column_bytes (stmt, 0); | ||
597 | dat = sqlite3_column_blob (stmt, 0); | ||
598 | exp.abs_value_us = sqlite3_column_int64 (stmt, 1); | ||
599 | psize = sqlite3_column_bytes (stmt, 2); | ||
600 | type = sqlite3_column_int (stmt, 3); | ||
601 | key = sqlite3_column_blob (stmt, 4); | ||
602 | if (0 != psize % sizeof (struct GNUNET_PeerIdentity)) | ||
603 | { | ||
604 | GNUNET_break (0); | ||
605 | psize = 0; | ||
606 | } | ||
607 | psize /= sizeof (struct GNUNET_PeerIdentity); | ||
608 | if (0 != psize) | ||
609 | path = sqlite3_column_blob (stmt, 2); | ||
610 | else | ||
611 | path = NULL; | ||
612 | ntime = (int64_t) exp.abs_value_us; | ||
613 | if (ntime == INT64_MAX) | ||
614 | exp = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
615 | cnt++; | ||
616 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
617 | "Found %u-byte result at %s when processing GET_CLOSE\n", | ||
618 | (unsigned int) size, | ||
619 | GNUNET_h2s (key)); | ||
620 | if (GNUNET_OK != iter (iter_cls, | ||
621 | key, | ||
622 | size, | ||
623 | dat, | ||
624 | type, | ||
625 | exp, | ||
626 | psize, | ||
627 | path)) | ||
628 | { | ||
629 | sqlite3_finalize (stmt); | ||
630 | break; | ||
631 | } | ||
632 | } | ||
633 | sqlite3_finalize (stmt); | ||
634 | return cnt; | ||
635 | } | ||
636 | |||
637 | |||
638 | /** | ||
525 | * Entry point for the plugin. | 639 | * Entry point for the plugin. |
526 | * | 640 | * |
527 | * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`) | 641 | * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`) |
@@ -595,6 +709,7 @@ libgnunet_plugin_datacache_sqlite_init (void *cls) | |||
595 | api->put = &sqlite_plugin_put; | 709 | api->put = &sqlite_plugin_put; |
596 | api->del = &sqlite_plugin_del; | 710 | api->del = &sqlite_plugin_del; |
597 | api->get_random = &sqlite_plugin_get_random; | 711 | api->get_random = &sqlite_plugin_get_random; |
712 | api->get_closest = &sqlite_plugin_get_closest; | ||
598 | LOG (GNUNET_ERROR_TYPE_INFO, | 713 | LOG (GNUNET_ERROR_TYPE_INFO, |
599 | "Sqlite datacache running\n"); | 714 | "Sqlite datacache running\n"); |
600 | return api; | 715 | return api; |