aboutsummaryrefslogtreecommitdiff
path: root/src/datacache
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-04-30 07:56:00 +0000
committerChristian Grothoff <christian@grothoff.org>2015-04-30 07:56:00 +0000
commit786745c969589eae2aa069885b40eba0f3989507 (patch)
tree6f5c8573b021ba628b4f135f3fb964728b3e1724 /src/datacache
parenta49b0f351926cf4376a58937a94e37426e3ae167 (diff)
downloadgnunet-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.c35
-rw-r--r--src/datacache/plugin_datacache_heap.c26
-rw-r--r--src/datacache/plugin_datacache_postgres.c137
-rw-r--r--src/datacache/plugin_datacache_sqlite.c115
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 */
391unsigned int
392GNUNET_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 */
428static unsigned int
429heap_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 */
527static unsigned int
528postgres_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 */
537static unsigned int
538sqlite_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;