diff options
author | David Barksdale <amatus@amat.us> | 2017-03-19 15:55:32 -0500 |
---|---|---|
committer | David Barksdale <amatus@amat.us> | 2017-03-19 17:38:36 -0500 |
commit | 2dde0202c5590eeb051c1346f2b66293d83b87ce (patch) | |
tree | 7997191912ee4c70959934d6c9783a0c9f450fec /src/datastore/plugin_datastore_sqlite.c | |
parent | d17d833dfd93a81f3540d472d1be4dfb7e9cbd03 (diff) | |
download | gnunet-2dde0202c5590eeb051c1346f2b66293d83b87ce.tar.gz gnunet-2dde0202c5590eeb051c1346f2b66293d83b87ce.zip |
[datastore] Fix #3743
This change adds support for key == NULL to the datastore plugins
and replaces the offset argument with a next_uid and random arguments to
increase performance in the key == NULL case.
With the offset argument a datastore plugin would have to count all
matching keys before fetching the key at the right offset, which would
iterate over the entire database in the case of key == NULL.
The offset argument was used in two ways: to iterate over a set of
matching values and to start iteration at a random matching value. The new API
seperates these into two arguments: if random is true it will return a
random matching value, otherwise next_uid can be set to uid + 1 to return the
next matching value.
The random argument was not added to get_zero_anonymity. This function
is used to periodically insert zero anonymity values into the DHT. I
don't think it's necessary to randomize this.
Diffstat (limited to 'src/datastore/plugin_datastore_sqlite.c')
-rw-r--r-- | src/datastore/plugin_datastore_sqlite.c | 261 |
1 files changed, 48 insertions, 213 deletions
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c index 9ca8f056a..76f791ad4 100644 --- a/src/datastore/plugin_datastore_sqlite.c +++ b/src/datastore/plugin_datastore_sqlite.c | |||
@@ -130,42 +130,7 @@ struct Plugin | |||
130 | /** | 130 | /** |
131 | * Precompiled SQL for selection | 131 | * Precompiled SQL for selection |
132 | */ | 132 | */ |
133 | sqlite3_stmt *count_key; | 133 | sqlite3_stmt *get; |
134 | |||
135 | /** | ||
136 | * Precompiled SQL for selection | ||
137 | */ | ||
138 | sqlite3_stmt *count_key_vhash; | ||
139 | |||
140 | /** | ||
141 | * Precompiled SQL for selection | ||
142 | */ | ||
143 | sqlite3_stmt *count_key_type; | ||
144 | |||
145 | /** | ||
146 | * Precompiled SQL for selection | ||
147 | */ | ||
148 | sqlite3_stmt *count_key_vhash_type; | ||
149 | |||
150 | /** | ||
151 | * Precompiled SQL for selection | ||
152 | */ | ||
153 | sqlite3_stmt *get_key; | ||
154 | |||
155 | /** | ||
156 | * Precompiled SQL for selection | ||
157 | */ | ||
158 | sqlite3_stmt *get_key_vhash; | ||
159 | |||
160 | /** | ||
161 | * Precompiled SQL for selection | ||
162 | */ | ||
163 | sqlite3_stmt *get_key_type; | ||
164 | |||
165 | /** | ||
166 | * Precompiled SQL for selection | ||
167 | */ | ||
168 | sqlite3_stmt *get_key_vhash_type; | ||
169 | 134 | ||
170 | /** | 135 | /** |
171 | * Should the database be dropped on shutdown? | 136 | * Should the database be dropped on shutdown? |
@@ -430,8 +395,10 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
430 | #if SQLITE_VERSION_NUMBER >= 3007000 | 395 | #if SQLITE_VERSION_NUMBER >= 3007000 |
431 | "INDEXED BY idx_anon_type_hash " | 396 | "INDEXED BY idx_anon_type_hash " |
432 | #endif | 397 | #endif |
433 | "WHERE (anonLevel = 0 AND type=?1) " | 398 | "WHERE _ROWID_ >= ? AND " |
434 | "ORDER BY hash DESC LIMIT 1 OFFSET ?2", | 399 | "anonLevel = 0 AND " |
400 | "type = ? " | ||
401 | "ORDER BY _ROWID_ ASC LIMIT 1", | ||
435 | &plugin->selZeroAnon)) || | 402 | &plugin->selZeroAnon)) || |
436 | (SQLITE_OK != | 403 | (SQLITE_OK != |
437 | sq_prepare (plugin->dbh, | 404 | sq_prepare (plugin->dbh, |
@@ -440,44 +407,14 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
440 | &plugin->insertContent)) || | 407 | &plugin->insertContent)) || |
441 | (SQLITE_OK != | 408 | (SQLITE_OK != |
442 | sq_prepare (plugin->dbh, | 409 | sq_prepare (plugin->dbh, |
443 | "SELECT count(*) FROM gn090 WHERE hash=?", | ||
444 | &plugin->count_key)) || | ||
445 | (SQLITE_OK != | ||
446 | sq_prepare (plugin->dbh, | ||
447 | "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=?", | ||
448 | &plugin->count_key_vhash)) || | ||
449 | (SQLITE_OK != | ||
450 | sq_prepare (plugin->dbh, | ||
451 | "SELECT count(*) FROM gn090 WHERE hash=? AND type=?", | ||
452 | &plugin->count_key_type)) || | ||
453 | (SQLITE_OK != | ||
454 | sq_prepare (plugin->dbh, | ||
455 | "SELECT count(*) FROM gn090 WHERE hash=? AND vhash=? AND type=?", | ||
456 | &plugin->count_key_vhash_type)) || | ||
457 | (SQLITE_OK != | ||
458 | sq_prepare (plugin->dbh, | ||
459 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | ||
460 | "WHERE hash=?" | ||
461 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
462 | &plugin->get_key)) || | ||
463 | (SQLITE_OK != | ||
464 | sq_prepare (plugin->dbh, | ||
465 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | ||
466 | "WHERE hash=? AND vhash=?" | ||
467 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
468 | &plugin->get_key_vhash)) || | ||
469 | (SQLITE_OK != | ||
470 | sq_prepare (plugin->dbh, | ||
471 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | 410 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " |
472 | "WHERE hash=? AND type=?" | 411 | "WHERE _ROWID_ >= ? AND " |
473 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | 412 | "(rvalue >= ? OR 0 = ?) AND " |
474 | &plugin->get_key_type)) || | 413 | "(hash = ? OR 0 = ?) AND " |
475 | (SQLITE_OK != | 414 | "(vhash = ? OR 0 = ?) AND " |
476 | sq_prepare (plugin->dbh, | 415 | "(type = ? OR 0 = ?) " |
477 | "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 " | 416 | "ORDER BY _ROWID_ ASC LIMIT 1", |
478 | "WHERE hash=? AND vhash=? AND type=?" | 417 | &plugin->get)) || |
479 | "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?", | ||
480 | &plugin->get_key_vhash_type)) || | ||
481 | (SQLITE_OK != | 418 | (SQLITE_OK != |
482 | sq_prepare (plugin->dbh, | 419 | sq_prepare (plugin->dbh, |
483 | "DELETE FROM gn090 WHERE _ROWID_ = ?", | 420 | "DELETE FROM gn090 WHERE _ROWID_ = ?", |
@@ -523,22 +460,8 @@ database_shutdown (struct Plugin *plugin) | |||
523 | sqlite3_finalize (plugin->selZeroAnon); | 460 | sqlite3_finalize (plugin->selZeroAnon); |
524 | if (NULL != plugin->insertContent) | 461 | if (NULL != plugin->insertContent) |
525 | sqlite3_finalize (plugin->insertContent); | 462 | sqlite3_finalize (plugin->insertContent); |
526 | if (NULL != plugin->count_key) | 463 | if (NULL != plugin->get) |
527 | sqlite3_finalize (plugin->count_key); | 464 | sqlite3_finalize (plugin->get); |
528 | if (NULL != plugin->count_key_vhash) | ||
529 | sqlite3_finalize (plugin->count_key_vhash); | ||
530 | if (NULL != plugin->count_key_type) | ||
531 | sqlite3_finalize (plugin->count_key_type); | ||
532 | if (NULL != plugin->count_key_vhash_type) | ||
533 | sqlite3_finalize (plugin->count_key_vhash_type); | ||
534 | if (NULL != plugin->count_key) | ||
535 | sqlite3_finalize (plugin->get_key); | ||
536 | if (NULL != plugin->count_key_vhash) | ||
537 | sqlite3_finalize (plugin->get_key_vhash); | ||
538 | if (NULL != plugin->count_key_type) | ||
539 | sqlite3_finalize (plugin->get_key_type); | ||
540 | if (NULL != plugin->count_key_vhash_type) | ||
541 | sqlite3_finalize (plugin->get_key_vhash_type); | ||
542 | result = sqlite3_close (plugin->dbh); | 465 | result = sqlite3_close (plugin->dbh); |
543 | #if SQLITE_VERSION_NUMBER >= 3007000 | 466 | #if SQLITE_VERSION_NUMBER >= 3007000 |
544 | if (result == SQLITE_BUSY) | 467 | if (result == SQLITE_BUSY) |
@@ -895,38 +818,36 @@ execute_get (struct Plugin *plugin, | |||
895 | * the given processor for the item. | 818 | * the given processor for the item. |
896 | * | 819 | * |
897 | * @param cls our plugin context | 820 | * @param cls our plugin context |
898 | * @param offset offset of the result (modulo num-results); | 821 | * @param next_uid return the result with lowest uid >= next_uid |
899 | * specific ordering does not matter for the offset | ||
900 | * @param type entries of which type should be considered? | 822 | * @param type entries of which type should be considered? |
901 | * Use 0 for any type. | 823 | * Must not be zero (ANY). |
902 | * @param proc function to call on each matching value; | 824 | * @param proc function to call on the matching value; |
903 | * will be called once with a NULL value at the end | 825 | * will be called with NULL if no value matches |
904 | * @param proc_cls closure for @a proc | 826 | * @param proc_cls closure for @a proc |
905 | */ | 827 | */ |
906 | static void | 828 | static void |
907 | sqlite_plugin_get_zero_anonymity (void *cls, | 829 | sqlite_plugin_get_zero_anonymity (void *cls, |
908 | uint64_t offset, | 830 | uint64_t next_uid, |
909 | enum GNUNET_BLOCK_Type type, | 831 | enum GNUNET_BLOCK_Type type, |
910 | PluginDatumProcessor proc, | 832 | PluginDatumProcessor proc, |
911 | void *proc_cls) | 833 | void *proc_cls) |
912 | { | 834 | { |
913 | struct Plugin *plugin = cls; | 835 | struct Plugin *plugin = cls; |
914 | struct GNUNET_SQ_QueryParam params[] = { | 836 | struct GNUNET_SQ_QueryParam params[] = { |
837 | GNUNET_SQ_query_param_uint64 (&next_uid), | ||
915 | GNUNET_SQ_query_param_uint32 (&type), | 838 | GNUNET_SQ_query_param_uint32 (&type), |
916 | GNUNET_SQ_query_param_uint64 (&offset), | ||
917 | GNUNET_SQ_query_param_end | 839 | GNUNET_SQ_query_param_end |
918 | }; | 840 | }; |
919 | sqlite3_stmt *stmt = plugin->selZeroAnon; | ||
920 | 841 | ||
921 | GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); | 842 | GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY); |
922 | if (GNUNET_OK != | 843 | if (GNUNET_OK != |
923 | GNUNET_SQ_bind (stmt, | 844 | GNUNET_SQ_bind (plugin->selZeroAnon, |
924 | params)) | 845 | params)) |
925 | { | 846 | { |
926 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 847 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
927 | return; | 848 | return; |
928 | } | 849 | } |
929 | execute_get (plugin, stmt, proc, proc_cls); | 850 | execute_get (plugin, plugin->selZeroAnon, proc, proc_cls); |
930 | } | 851 | } |
931 | 852 | ||
932 | 853 | ||
@@ -934,8 +855,9 @@ sqlite_plugin_get_zero_anonymity (void *cls, | |||
934 | * Get results for a particular key in the datastore. | 855 | * Get results for a particular key in the datastore. |
935 | * | 856 | * |
936 | * @param cls closure | 857 | * @param cls closure |
937 | * @param offset offset (mod count). | 858 | * @param next_uid return the result with lowest uid >= next_uid |
938 | * @param key key to match, never NULL | 859 | * @param random if true, return a random result instead of using next_uid |
860 | * @param key maybe NULL (to match all entries) | ||
939 | * @param vhash hash of the value, maybe NULL (to | 861 | * @param vhash hash of the value, maybe NULL (to |
940 | * match all values that have the right key). | 862 | * match all values that have the right key). |
941 | * Note that for DBlocks there is no difference | 863 | * Note that for DBlocks there is no difference |
@@ -949,7 +871,8 @@ sqlite_plugin_get_zero_anonymity (void *cls, | |||
949 | */ | 871 | */ |
950 | static void | 872 | static void |
951 | sqlite_plugin_get_key (void *cls, | 873 | sqlite_plugin_get_key (void *cls, |
952 | uint64_t offset, | 874 | uint64_t next_uid, |
875 | bool random, | ||
953 | const struct GNUNET_HashCode *key, | 876 | const struct GNUNET_HashCode *key, |
954 | const struct GNUNET_HashCode *vhash, | 877 | const struct GNUNET_HashCode *vhash, |
955 | enum GNUNET_BLOCK_Type type, | 878 | enum GNUNET_BLOCK_Type type, |
@@ -957,133 +880,45 @@ sqlite_plugin_get_key (void *cls, | |||
957 | void *proc_cls) | 880 | void *proc_cls) |
958 | { | 881 | { |
959 | struct Plugin *plugin = cls; | 882 | struct Plugin *plugin = cls; |
883 | uint64_t rvalue; | ||
884 | uint16_t use_rvalue = random; | ||
960 | uint32_t type32 = (uint32_t) type; | 885 | uint32_t type32 = (uint32_t) type; |
961 | int ret; | 886 | uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type; |
962 | int total; | 887 | uint16_t use_key = NULL != key; |
963 | uint32_t limit_off; | 888 | uint16_t use_vhash = NULL != vhash; |
964 | struct GNUNET_SQ_QueryParam count_params_key[] = { | 889 | struct GNUNET_SQ_QueryParam params[] = { |
965 | GNUNET_SQ_query_param_auto_from_type (key), | 890 | GNUNET_SQ_query_param_uint64 (&next_uid), |
966 | GNUNET_SQ_query_param_end | 891 | GNUNET_SQ_query_param_uint64 (&rvalue), |
967 | }; | 892 | GNUNET_SQ_query_param_uint16 (&use_rvalue), |
968 | struct GNUNET_SQ_QueryParam count_params_key_vhash[] = { | ||
969 | GNUNET_SQ_query_param_auto_from_type (key), | ||
970 | GNUNET_SQ_query_param_auto_from_type (vhash), | ||
971 | GNUNET_SQ_query_param_end | ||
972 | }; | ||
973 | struct GNUNET_SQ_QueryParam count_params_key_type[] = { | ||
974 | GNUNET_SQ_query_param_auto_from_type (key), | ||
975 | GNUNET_SQ_query_param_uint32 (&type32), | ||
976 | GNUNET_SQ_query_param_end | ||
977 | }; | ||
978 | struct GNUNET_SQ_QueryParam count_params_key_vhash_type[] = { | ||
979 | GNUNET_SQ_query_param_auto_from_type (key), | ||
980 | GNUNET_SQ_query_param_auto_from_type (vhash), | ||
981 | GNUNET_SQ_query_param_uint32 (&type32), | ||
982 | GNUNET_SQ_query_param_end | ||
983 | }; | ||
984 | struct GNUNET_SQ_QueryParam get_params_key[] = { | ||
985 | GNUNET_SQ_query_param_auto_from_type (key), | ||
986 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
987 | GNUNET_SQ_query_param_end | ||
988 | }; | ||
989 | struct GNUNET_SQ_QueryParam get_params_key_vhash[] = { | ||
990 | GNUNET_SQ_query_param_auto_from_type (key), | ||
991 | GNUNET_SQ_query_param_auto_from_type (vhash), | ||
992 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
993 | GNUNET_SQ_query_param_end | ||
994 | }; | ||
995 | struct GNUNET_SQ_QueryParam get_params_key_type[] = { | ||
996 | GNUNET_SQ_query_param_auto_from_type (key), | ||
997 | GNUNET_SQ_query_param_uint32 (&type32), | ||
998 | GNUNET_SQ_query_param_uint32 (&limit_off), | ||
999 | GNUNET_SQ_query_param_end | ||
1000 | }; | ||
1001 | struct GNUNET_SQ_QueryParam get_params_key_vhash_type[] = { | ||
1002 | GNUNET_SQ_query_param_auto_from_type (key), | 893 | GNUNET_SQ_query_param_auto_from_type (key), |
894 | GNUNET_SQ_query_param_uint16 (&use_key), | ||
1003 | GNUNET_SQ_query_param_auto_from_type (vhash), | 895 | GNUNET_SQ_query_param_auto_from_type (vhash), |
896 | GNUNET_SQ_query_param_uint16 (&use_vhash), | ||
1004 | GNUNET_SQ_query_param_uint32 (&type32), | 897 | GNUNET_SQ_query_param_uint32 (&type32), |
1005 | GNUNET_SQ_query_param_uint32 (&limit_off), | 898 | GNUNET_SQ_query_param_uint16 (&use_type), |
1006 | GNUNET_SQ_query_param_end | 899 | GNUNET_SQ_query_param_end |
1007 | }; | 900 | }; |
1008 | struct GNUNET_SQ_QueryParam *count_params; | ||
1009 | sqlite3_stmt *count_stmt; | ||
1010 | struct GNUNET_SQ_QueryParam *get_params; | ||
1011 | sqlite3_stmt *get_stmt; | ||
1012 | 901 | ||
1013 | if (NULL == vhash) | 902 | if (random) |
1014 | { | 903 | { |
1015 | if (GNUNET_BLOCK_TYPE_ANY == type) | 904 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, |
1016 | { | 905 | UINT64_MAX); |
1017 | count_params = count_params_key; | 906 | next_uid = 0; |
1018 | count_stmt = plugin->count_key; | ||
1019 | get_params = get_params_key; | ||
1020 | get_stmt = plugin->get_key; | ||
1021 | } | ||
1022 | else | ||
1023 | { | ||
1024 | count_params = count_params_key_type; | ||
1025 | count_stmt = plugin->count_key_type; | ||
1026 | get_params = get_params_key_type; | ||
1027 | get_stmt = plugin->get_key_type; | ||
1028 | } | ||
1029 | } | 907 | } |
1030 | else | 908 | else |
1031 | { | 909 | rvalue = 0; |
1032 | if (GNUNET_BLOCK_TYPE_ANY == type) | 910 | |
1033 | { | ||
1034 | count_params = count_params_key_vhash; | ||
1035 | count_stmt = plugin->count_key_vhash; | ||
1036 | get_params = get_params_key_vhash; | ||
1037 | get_stmt = plugin->get_key_vhash; | ||
1038 | } | ||
1039 | else | ||
1040 | { | ||
1041 | count_params = count_params_key_vhash_type; | ||
1042 | count_stmt = plugin->count_key_vhash_type; | ||
1043 | get_params = get_params_key_vhash_type; | ||
1044 | get_stmt = plugin->get_key_vhash_type; | ||
1045 | } | ||
1046 | } | ||
1047 | if (GNUNET_OK != | ||
1048 | GNUNET_SQ_bind (count_stmt, | ||
1049 | count_params)) | ||
1050 | { | ||
1051 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
1052 | return; | ||
1053 | } | ||
1054 | ret = sqlite3_step (count_stmt); | ||
1055 | if (ret != SQLITE_ROW) | ||
1056 | { | ||
1057 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1058 | "sqlite_step"); | ||
1059 | GNUNET_SQ_reset (plugin->dbh, | ||
1060 | count_stmt); | ||
1061 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
1062 | return; | ||
1063 | } | ||
1064 | total = sqlite3_column_int (count_stmt, | ||
1065 | 0); | ||
1066 | GNUNET_SQ_reset (plugin->dbh, | ||
1067 | count_stmt); | ||
1068 | if (0 == total) | ||
1069 | { | ||
1070 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | ||
1071 | return; | ||
1072 | } | ||
1073 | limit_off = (uint32_t) (offset % total); | ||
1074 | if (GNUNET_OK != | 911 | if (GNUNET_OK != |
1075 | GNUNET_SQ_bind (get_stmt, | 912 | GNUNET_SQ_bind (plugin->get, |
1076 | get_params)) | 913 | params)) |
1077 | { | 914 | { |
1078 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); | 915 | proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); |
1079 | return; | 916 | return; |
1080 | } | 917 | } |
1081 | execute_get (plugin, | 918 | execute_get (plugin, |
1082 | get_stmt, | 919 | plugin->get, |
1083 | proc, | 920 | proc, |
1084 | proc_cls); | 921 | proc_cls); |
1085 | GNUNET_SQ_reset (plugin->dbh, | ||
1086 | get_stmt); | ||
1087 | } | 922 | } |
1088 | 923 | ||
1089 | 924 | ||