diff options
Diffstat (limited to 'src/datastore/plugin_datastore_postgres.c')
-rw-r--r-- | src/datastore/plugin_datastore_postgres.c | 233 |
1 files changed, 53 insertions, 180 deletions
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c index 8b8737935..0376ebb6c 100644 --- a/src/datastore/plugin_datastore_postgres.c +++ b/src/datastore/plugin_datastore_postgres.c | |||
@@ -80,6 +80,7 @@ init_connection (struct Plugin *plugin) | |||
80 | * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel | 80 | * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel |
81 | * we do math or inequality tests, so we can't handle the entire range of uint32_t. | 81 | * we do math or inequality tests, so we can't handle the entire range of uint32_t. |
82 | * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. | 82 | * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. |
83 | * PostgreSQL also recommends against using WITH OIDS. | ||
83 | */ | 84 | */ |
84 | ret = | 85 | ret = |
85 | PQexec (plugin->dbh, | 86 | PQexec (plugin->dbh, |
@@ -176,40 +177,18 @@ init_connection (struct Plugin *plugin) | |||
176 | } | 177 | } |
177 | PQclear (ret); | 178 | PQclear (ret); |
178 | if ((GNUNET_OK != | 179 | if ((GNUNET_OK != |
179 | GNUNET_POSTGRES_prepare (plugin->dbh, "getvt", | ||
180 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " | ||
181 | "WHERE hash=$1 AND vhash=$2 AND type=$3 " | ||
182 | "ORDER BY oid ASC LIMIT 1 OFFSET $4", 4)) || | ||
183 | (GNUNET_OK != | ||
184 | GNUNET_POSTGRES_prepare (plugin->dbh, "gett", | ||
185 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " | ||
186 | "WHERE hash=$1 AND type=$2 " | ||
187 | "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) || | ||
188 | (GNUNET_OK != | ||
189 | GNUNET_POSTGRES_prepare (plugin->dbh, "getv", | ||
190 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " | ||
191 | "WHERE hash=$1 AND vhash=$2 " | ||
192 | "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) || | ||
193 | (GNUNET_OK != | ||
194 | GNUNET_POSTGRES_prepare (plugin->dbh, "get", | 180 | GNUNET_POSTGRES_prepare (plugin->dbh, "get", |
195 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " | 181 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " |
196 | "WHERE hash=$1 " "ORDER BY oid ASC LIMIT 1 OFFSET $2", 2)) || | 182 | "WHERE oid >= $1::bigint AND " |
197 | (GNUNET_OK != | 183 | "(rvalue >= $2 OR 0 = $3::smallint) AND " |
198 | GNUNET_POSTGRES_prepare (plugin->dbh, "count_getvt", | 184 | "(hash = $4 OR 0 = $5::smallint) AND " |
199 | "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2 AND type=$3", 3)) || | 185 | "(vhash = $6 OR 0 = $7::smallint) AND " |
200 | (GNUNET_OK != | 186 | "(type = $8 OR 0 = $9::smallint) " |
201 | GNUNET_POSTGRES_prepare (plugin->dbh, "count_gett", | 187 | "ORDER BY oid ASC LIMIT 1", 9)) || |
202 | "SELECT count(*) FROM gn090 WHERE hash=$1 AND type=$2", 2)) || | ||
203 | (GNUNET_OK != | ||
204 | GNUNET_POSTGRES_prepare (plugin->dbh, "count_getv", | ||
205 | "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2", 2)) || | ||
206 | (GNUNET_OK != | ||
207 | GNUNET_POSTGRES_prepare (plugin->dbh, "count_get", | ||
208 | "SELECT count(*) FROM gn090 WHERE hash=$1", 1)) || | ||
209 | (GNUNET_OK != | 188 | (GNUNET_OK != |
210 | GNUNET_POSTGRES_prepare (plugin->dbh, "put", | 189 | GNUNET_POSTGRES_prepare (plugin->dbh, "put", |
211 | "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " | 190 | "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " |
212 | "VALUES ($1, $2, $3, $4, $5, RANDOM(), $6, $7, $8)", 9)) || | 191 | "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", 9)) || |
213 | (GNUNET_OK != | 192 | (GNUNET_OK != |
214 | GNUNET_POSTGRES_prepare (plugin->dbh, "update", | 193 | GNUNET_POSTGRES_prepare (plugin->dbh, "update", |
215 | "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END " | 194 | "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END " |
@@ -221,8 +200,9 @@ init_connection (struct Plugin *plugin) | |||
221 | (GNUNET_OK != | 200 | (GNUNET_OK != |
222 | GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous", | 201 | GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous", |
223 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " | 202 | "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " |
224 | "WHERE anonLevel = 0 AND type = $1 ORDER BY oid DESC LIMIT 1 OFFSET $2", | 203 | "WHERE anonLevel = 0 AND type = $1 AND oid >= $2::bigint " |
225 | 1)) || | 204 | "ORDER BY oid ASC LIMIT 1", |
205 | 2)) || | ||
226 | (GNUNET_OK != | 206 | (GNUNET_OK != |
227 | GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order", | 207 | GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order", |
228 | "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " | 208 | "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 " |
@@ -328,6 +308,8 @@ postgres_plugin_put (void *cls, | |||
328 | struct Plugin *plugin = cls; | 308 | struct Plugin *plugin = cls; |
329 | uint32_t utype = type; | 309 | uint32_t utype = type; |
330 | struct GNUNET_HashCode vhash; | 310 | struct GNUNET_HashCode vhash; |
311 | uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
312 | UINT64_MAX); | ||
331 | PGresult *ret; | 313 | PGresult *ret; |
332 | struct GNUNET_PQ_QueryParam params[] = { | 314 | struct GNUNET_PQ_QueryParam params[] = { |
333 | GNUNET_PQ_query_param_uint32 (&replication), | 315 | GNUNET_PQ_query_param_uint32 (&replication), |
@@ -335,6 +317,7 @@ postgres_plugin_put (void *cls, | |||
335 | GNUNET_PQ_query_param_uint32 (&priority), | 317 | GNUNET_PQ_query_param_uint32 (&priority), |
336 | GNUNET_PQ_query_param_uint32 (&anonymity), | 318 | GNUNET_PQ_query_param_uint32 (&anonymity), |
337 | GNUNET_PQ_query_param_absolute_time (&expiration), | 319 | GNUNET_PQ_query_param_absolute_time (&expiration), |
320 | GNUNET_PQ_query_param_uint64 (&rvalue), | ||
338 | GNUNET_PQ_query_param_auto_from_type (key), | 321 | GNUNET_PQ_query_param_auto_from_type (key), |
339 | GNUNET_PQ_query_param_auto_from_type (&vhash), | 322 | GNUNET_PQ_query_param_auto_from_type (&vhash), |
340 | GNUNET_PQ_query_param_fixed_size (data, size), | 323 | GNUNET_PQ_query_param_fixed_size (data, size), |
@@ -495,12 +478,11 @@ process_result (struct Plugin *plugin, | |||
495 | 478 | ||
496 | 479 | ||
497 | /** | 480 | /** |
498 | * Iterate over the results for a particular key | 481 | * Get one of the results for a particular key in the datastore. |
499 | * in the datastore. | ||
500 | * | 482 | * |
501 | * @param cls closure with the 'struct Plugin' | 483 | * @param cls closure with the 'struct Plugin' |
502 | * @param offset offset of the result (modulo num-results); | 484 | * @param next_uid return the result with lowest uid >= next_uid |
503 | * specific ordering does not matter for the offset | 485 | * @param random if true, return a random result instead of using next_uid |
504 | * @param key maybe NULL (to match all entries) | 486 | * @param key maybe NULL (to match all entries) |
505 | * @param vhash hash of the value, maybe NULL (to | 487 | * @param vhash hash of the value, maybe NULL (to |
506 | * match all values that have the right key). | 488 | * match all values that have the right key). |
@@ -510,160 +492,52 @@ process_result (struct Plugin *plugin, | |||
510 | * @param type entries of which type are relevant? | 492 | * @param type entries of which type are relevant? |
511 | * Use 0 for any type. | 493 | * Use 0 for any type. |
512 | * @param proc function to call on the matching value; | 494 | * @param proc function to call on the matching value; |
513 | * will be called once with a NULL if no value matches | 495 | * will be called with NULL if nothing matches |
514 | * @param proc_cls closure for iter | 496 | * @param proc_cls closure for @a proc |
515 | */ | 497 | */ |
516 | static void | 498 | static void |
517 | postgres_plugin_get_key (void *cls, | 499 | postgres_plugin_get_key (void *cls, |
518 | uint64_t offset, | 500 | uint64_t next_uid, |
501 | bool random, | ||
519 | const struct GNUNET_HashCode *key, | 502 | const struct GNUNET_HashCode *key, |
520 | const struct GNUNET_HashCode *vhash, | 503 | const struct GNUNET_HashCode *vhash, |
521 | enum GNUNET_BLOCK_Type type, | 504 | enum GNUNET_BLOCK_Type type, |
522 | PluginDatumProcessor proc, | 505 | PluginDatumProcessor proc, |
523 | void *proc_cls) | 506 | void *proc_cls) |
524 | { | 507 | { |
525 | struct Plugin *plugin = cls; | 508 | struct Plugin *plugin = cls; |
526 | uint32_t utype = type; | 509 | uint32_t utype = type; |
510 | uint16_t use_rvalue = random; | ||
511 | uint16_t use_key = NULL != key; | ||
512 | uint16_t use_vhash = NULL != vhash; | ||
513 | uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type; | ||
514 | uint64_t rvalue; | ||
515 | struct GNUNET_PQ_QueryParam params[] = { | ||
516 | GNUNET_PQ_query_param_uint64 (&next_uid), | ||
517 | GNUNET_PQ_query_param_uint64 (&rvalue), | ||
518 | GNUNET_PQ_query_param_uint16 (&use_rvalue), | ||
519 | GNUNET_PQ_query_param_auto_from_type (key), | ||
520 | GNUNET_PQ_query_param_uint16 (&use_key), | ||
521 | GNUNET_PQ_query_param_auto_from_type (vhash), | ||
522 | GNUNET_PQ_query_param_uint16 (&use_vhash), | ||
523 | GNUNET_PQ_query_param_uint32 (&utype), | ||
524 | GNUNET_PQ_query_param_uint16 (&use_type), | ||
525 | GNUNET_PQ_query_param_end | ||
526 | }; | ||
527 | PGresult *ret; | 527 | PGresult *ret; |
528 | uint64_t total; | ||
529 | uint64_t limit_off; | ||
530 | 528 | ||
531 | if (0 != type) | 529 | if (random) |
532 | { | 530 | { |
533 | if (NULL != vhash) | 531 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, |
534 | { | 532 | UINT64_MAX); |
535 | struct GNUNET_PQ_QueryParam params[] = { | 533 | next_uid = 0; |
536 | GNUNET_PQ_query_param_auto_from_type (key), | ||
537 | GNUNET_PQ_query_param_auto_from_type (vhash), | ||
538 | GNUNET_PQ_query_param_uint32 (&utype), | ||
539 | GNUNET_PQ_query_param_end | ||
540 | }; | ||
541 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
542 | "count_getvt", | ||
543 | params); | ||
544 | } | ||
545 | else | ||
546 | { | ||
547 | struct GNUNET_PQ_QueryParam params[] = { | ||
548 | GNUNET_PQ_query_param_auto_from_type (key), | ||
549 | GNUNET_PQ_query_param_uint32 (&utype), | ||
550 | GNUNET_PQ_query_param_end | ||
551 | }; | ||
552 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
553 | "count_gett", | ||
554 | params); | ||
555 | } | ||
556 | } | 534 | } |
557 | else | 535 | else |
558 | { | 536 | rvalue = 0; |
559 | if (NULL != vhash) | ||
560 | { | ||
561 | struct GNUNET_PQ_QueryParam params[] = { | ||
562 | GNUNET_PQ_query_param_auto_from_type (key), | ||
563 | GNUNET_PQ_query_param_auto_from_type (vhash), | ||
564 | GNUNET_PQ_query_param_end | ||
565 | }; | ||
566 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
567 | "count_getv", | ||
568 | params); | ||
569 | } | ||
570 | else | ||
571 | { | ||
572 | struct GNUNET_PQ_QueryParam params[] = { | ||
573 | GNUNET_PQ_query_param_auto_from_type (key), | ||
574 | GNUNET_PQ_query_param_end | ||
575 | }; | ||
576 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
577 | "count_get", | ||
578 | params); | ||
579 | } | ||
580 | } | ||
581 | 537 | ||
582 | if (GNUNET_OK != | 538 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, |
583 | GNUNET_POSTGRES_check_result (plugin->dbh, | 539 | "get", |
584 | ret, | 540 | params); |
585 | PGRES_TUPLES_OK, | ||
586 | "PQexecParams", | ||
587 | "count")) | ||
588 | { | ||
589 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, | ||
590 | GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
591 | return; | ||
592 | } | ||
593 | if ( (PQntuples (ret) != 1) || | ||
594 | (PQnfields (ret) != 1) || | ||
595 | (PQgetlength (ret, 0, 0) != sizeof (uint64_t))) | ||
596 | { | ||
597 | GNUNET_break (0); | ||
598 | PQclear (ret); | ||
599 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, | ||
600 | GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
601 | return; | ||
602 | } | ||
603 | total = GNUNET_ntohll (*(const uint64_t *) PQgetvalue (ret, 0, 0)); | ||
604 | PQclear (ret); | ||
605 | if (0 == total) | ||
606 | { | ||
607 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, | ||
608 | GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
609 | return; | ||
610 | } | ||
611 | limit_off = offset % total; | ||
612 | |||
613 | if (0 != type) | ||
614 | { | ||
615 | if (NULL != vhash) | ||
616 | { | ||
617 | struct GNUNET_PQ_QueryParam params[] = { | ||
618 | GNUNET_PQ_query_param_auto_from_type (key), | ||
619 | GNUNET_PQ_query_param_auto_from_type (vhash), | ||
620 | GNUNET_PQ_query_param_uint32 (&utype), | ||
621 | GNUNET_PQ_query_param_uint64 (&limit_off), | ||
622 | GNUNET_PQ_query_param_end | ||
623 | }; | ||
624 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
625 | "getvt", | ||
626 | params); | ||
627 | } | ||
628 | else | ||
629 | { | ||
630 | struct GNUNET_PQ_QueryParam params[] = { | ||
631 | GNUNET_PQ_query_param_auto_from_type (key), | ||
632 | GNUNET_PQ_query_param_uint32 (&utype), | ||
633 | GNUNET_PQ_query_param_uint64 (&limit_off), | ||
634 | GNUNET_PQ_query_param_end | ||
635 | }; | ||
636 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
637 | "gett", | ||
638 | params); | ||
639 | } | ||
640 | } | ||
641 | else | ||
642 | { | ||
643 | if (NULL != vhash) | ||
644 | { | ||
645 | struct GNUNET_PQ_QueryParam params[] = { | ||
646 | GNUNET_PQ_query_param_auto_from_type (key), | ||
647 | GNUNET_PQ_query_param_auto_from_type (vhash), | ||
648 | GNUNET_PQ_query_param_uint64 (&limit_off), | ||
649 | GNUNET_PQ_query_param_end | ||
650 | }; | ||
651 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
652 | "getv", | ||
653 | params); | ||
654 | } | ||
655 | else | ||
656 | { | ||
657 | struct GNUNET_PQ_QueryParam params[] = { | ||
658 | GNUNET_PQ_query_param_auto_from_type (key), | ||
659 | GNUNET_PQ_query_param_uint64 (&limit_off), | ||
660 | GNUNET_PQ_query_param_end | ||
661 | }; | ||
662 | ret = GNUNET_PQ_exec_prepared (plugin->dbh, | ||
663 | "get", | ||
664 | params); | ||
665 | } | ||
666 | } | ||
667 | process_result (plugin, | 541 | process_result (plugin, |
668 | proc, | 542 | proc, |
669 | proc_cls, | 543 | proc_cls, |
@@ -677,26 +551,25 @@ postgres_plugin_get_key (void *cls, | |||
677 | * the given iterator for each of them. | 551 | * the given iterator for each of them. |
678 | * | 552 | * |
679 | * @param cls our `struct Plugin *` | 553 | * @param cls our `struct Plugin *` |
680 | * @param offset offset of the result (modulo num-results); | 554 | * @param next_uid return the result with lowest uid >= next_uid |
681 | * specific ordering does not matter for the offset | ||
682 | * @param type entries of which type should be considered? | 555 | * @param type entries of which type should be considered? |
683 | * Use 0 for any type. | 556 | * Must not be zero (ANY). |
684 | * @param proc function to call on the matching value; | 557 | * @param proc function to call on the matching value; |
685 | * will be called with a NULL if no value matches | 558 | * will be called with NULL if no value matches |
686 | * @param proc_cls closure for @a proc | 559 | * @param proc_cls closure for @a proc |
687 | */ | 560 | */ |
688 | static void | 561 | static void |
689 | postgres_plugin_get_zero_anonymity (void *cls, | 562 | postgres_plugin_get_zero_anonymity (void *cls, |
690 | uint64_t offset, | 563 | uint64_t next_uid, |
691 | enum GNUNET_BLOCK_Type type, | 564 | enum GNUNET_BLOCK_Type type, |
692 | PluginDatumProcessor proc, | 565 | PluginDatumProcessor proc, |
693 | void *proc_cls) | 566 | void *proc_cls) |
694 | { | 567 | { |
695 | struct Plugin *plugin = cls; | 568 | struct Plugin *plugin = cls; |
696 | uint32_t utype = type; | 569 | uint32_t utype = type; |
697 | struct GNUNET_PQ_QueryParam params[] = { | 570 | struct GNUNET_PQ_QueryParam params[] = { |
698 | GNUNET_PQ_query_param_uint32 (&utype), | 571 | GNUNET_PQ_query_param_uint32 (&utype), |
699 | GNUNET_PQ_query_param_uint64 (&offset), | 572 | GNUNET_PQ_query_param_uint64 (&next_uid), |
700 | GNUNET_PQ_query_param_end | 573 | GNUNET_PQ_query_param_end |
701 | }; | 574 | }; |
702 | PGresult *ret; | 575 | PGresult *ret; |