diff options
Diffstat (limited to 'src/namestore/plugin_namestore_sqlite.c')
-rw-r--r-- | src/namestore/plugin_namestore_sqlite.c | 243 |
1 files changed, 174 insertions, 69 deletions
diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c index c63339db7..f1097ad0a 100644 --- a/src/namestore/plugin_namestore_sqlite.c +++ b/src/namestore/plugin_namestore_sqlite.c | |||
@@ -75,6 +75,11 @@ struct Plugin | |||
75 | char *fn; | 75 | char *fn; |
76 | 76 | ||
77 | /** | 77 | /** |
78 | * Statements prepared, we are ready to go if GNUNET_YES | ||
79 | */ | ||
80 | int ready; | ||
81 | |||
82 | /** | ||
78 | * Native SQLite database handle. | 83 | * Native SQLite database handle. |
79 | */ | 84 | */ |
80 | sqlite3 *dbh; | 85 | sqlite3 *dbh; |
@@ -120,9 +125,10 @@ struct Plugin | |||
120 | * @return #GNUNET_OK on success | 125 | * @return #GNUNET_OK on success |
121 | */ | 126 | */ |
122 | static int | 127 | static int |
123 | database_setup (struct Plugin *plugin) | 128 | database_prepare (struct Plugin *plugin) |
124 | { | 129 | { |
125 | char *sqlite_filename; | 130 | if (GNUNET_YES == plugin->ready) |
131 | return GNUNET_OK; | ||
126 | struct GNUNET_SQ_ExecuteStatement es[] = { | 132 | struct GNUNET_SQ_ExecuteStatement es[] = { |
127 | GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"), | 133 | GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"), |
128 | GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"), | 134 | GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"), |
@@ -132,19 +138,6 @@ database_setup (struct Plugin *plugin) | |||
132 | GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"), | 138 | GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"), |
133 | GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"), | 139 | GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"), |
134 | GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"), | 140 | GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"), |
135 | GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records (" | ||
136 | " uid INTEGER PRIMARY KEY," | ||
137 | " zone_private_key BLOB NOT NULL," | ||
138 | " pkey BLOB," | ||
139 | " rvalue INT8 NOT NULL," | ||
140 | " record_count INT NOT NULL," | ||
141 | " record_data BLOB NOT NULL," | ||
142 | " label TEXT NOT NULL" | ||
143 | ")"), | ||
144 | GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse " | ||
145 | "ON ns098records (zone_private_key,pkey)"), | ||
146 | GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter " | ||
147 | "ON ns098records (zone_private_key,uid)"), | ||
148 | GNUNET_SQ_EXECUTE_STATEMENT_END | 141 | GNUNET_SQ_EXECUTE_STATEMENT_END |
149 | }; | 142 | }; |
150 | struct GNUNET_SQ_PrepareStatement ps[] = { | 143 | struct GNUNET_SQ_PrepareStatement ps[] = { |
@@ -180,65 +173,25 @@ database_setup (struct Plugin *plugin) | |||
180 | }; | 173 | }; |
181 | 174 | ||
182 | if (GNUNET_OK != | 175 | if (GNUNET_OK != |
183 | GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, | ||
184 | "namestore-sqlite", | ||
185 | "FILENAME", | ||
186 | &sqlite_filename)) | ||
187 | { | ||
188 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
189 | "namestore-sqlite", | ||
190 | "FILENAME"); | ||
191 | return GNUNET_SYSERR; | ||
192 | } | ||
193 | if (GNUNET_OK != | ||
194 | GNUNET_DISK_file_test (sqlite_filename)) | ||
195 | { | ||
196 | if (GNUNET_OK != | ||
197 | GNUNET_DISK_directory_create_for_file (sqlite_filename)) | ||
198 | { | ||
199 | GNUNET_break (0); | ||
200 | GNUNET_free (sqlite_filename); | ||
201 | return GNUNET_SYSERR; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* Open database and precompile statements */ | ||
206 | if (SQLITE_OK != | ||
207 | sqlite3_open (sqlite_filename, | ||
208 | &plugin->dbh)) | ||
209 | { | ||
210 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
211 | _ ("Unable to initialize SQLite: %s.\n"), | ||
212 | sqlite3_errmsg (plugin->dbh)); | ||
213 | GNUNET_free (sqlite_filename); | ||
214 | return GNUNET_SYSERR; | ||
215 | } | ||
216 | GNUNET_break (SQLITE_OK == | ||
217 | sqlite3_busy_timeout (plugin->dbh, | ||
218 | BUSY_TIMEOUT_MS)); | ||
219 | if (GNUNET_OK != | ||
220 | GNUNET_SQ_exec_statements (plugin->dbh, | 176 | GNUNET_SQ_exec_statements (plugin->dbh, |
221 | es)) | 177 | es)) |
222 | { | 178 | { |
223 | GNUNET_break (0); | ||
224 | LOG (GNUNET_ERROR_TYPE_ERROR, | 179 | LOG (GNUNET_ERROR_TYPE_ERROR, |
225 | _ ("Failed to setup database at `%s'\n"), | 180 | _("Failed to setup database with: `%s'\n"), |
226 | sqlite_filename); | 181 | sqlite3_errmsg (plugin->dbh)); |
227 | GNUNET_free (sqlite_filename); | ||
228 | return GNUNET_SYSERR; | 182 | return GNUNET_SYSERR; |
229 | } | 183 | } |
230 | |||
231 | if (GNUNET_OK != | 184 | if (GNUNET_OK != |
232 | GNUNET_SQ_prepare (plugin->dbh, | 185 | GNUNET_SQ_prepare (plugin->dbh, |
233 | ps)) | 186 | ps)) |
234 | { | 187 | { |
235 | GNUNET_break (0); | 188 | GNUNET_break (0); |
236 | LOG (GNUNET_ERROR_TYPE_ERROR, | 189 | LOG (GNUNET_ERROR_TYPE_ERROR, |
237 | _ ("Failed to setup database at `%s'\n"), | 190 | _ ("Failed to setup database with: `%s'\n"), |
238 | sqlite_filename); | 191 | sqlite3_errmsg (plugin->dbh)); |
239 | GNUNET_free (sqlite_filename); | ||
240 | return GNUNET_SYSERR; | 192 | return GNUNET_SYSERR; |
241 | } | 193 | } |
194 | plugin->ready = GNUNET_YES; | ||
242 | return GNUNET_OK; | 195 | return GNUNET_OK; |
243 | } | 196 | } |
244 | 197 | ||
@@ -325,6 +278,7 @@ namestore_sqlite_store_records (void *cls, | |||
325 | uint64_t rvalue; | 278 | uint64_t rvalue; |
326 | ssize_t data_size; | 279 | ssize_t data_size; |
327 | 280 | ||
281 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
328 | memset (&pkey, | 282 | memset (&pkey, |
329 | 0, | 283 | 0, |
330 | sizeof(pkey)); | 284 | sizeof(pkey)); |
@@ -594,6 +548,7 @@ namestore_sqlite_lookup_records (void *cls, | |||
594 | void *iter_cls) | 548 | void *iter_cls) |
595 | { | 549 | { |
596 | struct Plugin *plugin = cls; | 550 | struct Plugin *plugin = cls; |
551 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
597 | struct GNUNET_SQ_QueryParam params[] = { | 552 | struct GNUNET_SQ_QueryParam params[] = { |
598 | GNUNET_SQ_query_param_auto_from_type (zone), | 553 | GNUNET_SQ_query_param_auto_from_type (zone), |
599 | GNUNET_SQ_query_param_string (label), | 554 | GNUNET_SQ_query_param_string (label), |
@@ -649,6 +604,7 @@ namestore_sqlite_iterate_records (void *cls, | |||
649 | sqlite3_stmt *stmt; | 604 | sqlite3_stmt *stmt; |
650 | int err; | 605 | int err; |
651 | 606 | ||
607 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
652 | if (NULL == zone) | 608 | if (NULL == zone) |
653 | { | 609 | { |
654 | struct GNUNET_SQ_QueryParam params[] = { | 610 | struct GNUNET_SQ_QueryParam params[] = { |
@@ -712,6 +668,7 @@ namestore_sqlite_zone_to_name (void *cls, | |||
712 | void *iter_cls) | 668 | void *iter_cls) |
713 | { | 669 | { |
714 | struct Plugin *plugin = cls; | 670 | struct Plugin *plugin = cls; |
671 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
715 | struct GNUNET_SQ_QueryParam params[] = { | 672 | struct GNUNET_SQ_QueryParam params[] = { |
716 | GNUNET_SQ_query_param_auto_from_type (zone), | 673 | GNUNET_SQ_query_param_auto_from_type (zone), |
717 | GNUNET_SQ_query_param_auto_from_type (value_zone), | 674 | GNUNET_SQ_query_param_auto_from_type (value_zone), |
@@ -755,8 +712,11 @@ namestore_sqlite_transaction_begin (void *cls, | |||
755 | char **emsg) | 712 | char **emsg) |
756 | { | 713 | { |
757 | struct Plugin *plugin = cls; | 714 | struct Plugin *plugin = cls; |
758 | return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "BEGIN IMMEDIATE TRANSACTION;", NULL, | 715 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); |
759 | NULL, emsg)) ? GNUNET_SYSERR : GNUNET_YES; | 716 | return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, |
717 | "BEGIN IMMEDIATE TRANSACTION;", NULL, | ||
718 | NULL, emsg)) ? GNUNET_SYSERR : | ||
719 | GNUNET_YES; | ||
760 | } | 720 | } |
761 | 721 | ||
762 | /** | 722 | /** |
@@ -772,8 +732,10 @@ namestore_sqlite_transaction_rollback (void *cls, | |||
772 | char **emsg) | 732 | char **emsg) |
773 | { | 733 | { |
774 | struct Plugin *plugin = cls; | 734 | struct Plugin *plugin = cls; |
735 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
775 | return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "ROLLBACK;", NULL, | 736 | return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "ROLLBACK;", NULL, |
776 | NULL, emsg)) ? GNUNET_SYSERR : GNUNET_YES; | 737 | NULL, emsg)) ? GNUNET_SYSERR : |
738 | GNUNET_YES; | ||
777 | } | 739 | } |
778 | 740 | ||
779 | /** | 741 | /** |
@@ -789,11 +751,151 @@ namestore_sqlite_transaction_commit (void *cls, | |||
789 | char **emsg) | 751 | char **emsg) |
790 | { | 752 | { |
791 | struct Plugin *plugin = cls; | 753 | struct Plugin *plugin = cls; |
754 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
792 | return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "END TRANSACTION;", NULL, | 755 | return (SQLITE_BUSY == sqlite3_exec (plugin->dbh, "END TRANSACTION;", NULL, |
793 | NULL, emsg)) ? GNUNET_SYSERR : GNUNET_YES; | 756 | NULL, emsg)) ? GNUNET_SYSERR : |
757 | GNUNET_YES; | ||
758 | } | ||
759 | |||
760 | static enum GNUNET_GenericReturnValue | ||
761 | init_database (void *cls, char **emsg, int drop) | ||
762 | { | ||
763 | struct Plugin *plugin = cls; | ||
764 | struct GNUNET_SQ_ExecuteStatement es_drop[] = { | ||
765 | GNUNET_SQ_make_execute ("DROP TABLE IF EXISTS ns098records"), | ||
766 | GNUNET_SQ_EXECUTE_STATEMENT_END | ||
767 | }; | ||
768 | struct GNUNET_SQ_ExecuteStatement es[] = { | ||
769 | GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"), | ||
770 | GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"), | ||
771 | GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"), | ||
772 | GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"), | ||
773 | GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""), | ||
774 | GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"), | ||
775 | GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"), | ||
776 | GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"), | ||
777 | GNUNET_SQ_make_execute ("CREATE TABLE ns098records (" | ||
778 | " uid INTEGER PRIMARY KEY," | ||
779 | " zone_private_key BLOB NOT NULL," | ||
780 | " pkey BLOB," | ||
781 | " rvalue INT8 NOT NULL," | ||
782 | " record_count INT NOT NULL," | ||
783 | " record_data BLOB NOT NULL," | ||
784 | " label TEXT NOT NULL" | ||
785 | ")"), | ||
786 | GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse " | ||
787 | "ON ns098records (zone_private_key,pkey)"), | ||
788 | GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_iter " | ||
789 | "ON ns098records (zone_private_key,uid)"), | ||
790 | GNUNET_SQ_EXECUTE_STATEMENT_END | ||
791 | }; | ||
792 | if ((GNUNET_YES == drop) && | ||
793 | (GNUNET_OK != GNUNET_SQ_exec_statements (plugin->dbh, | ||
794 | es_drop))) | ||
795 | { | ||
796 | GNUNET_asprintf (emsg, | ||
797 | _ ("Failed to drop database with: `%s'\n"), | ||
798 | sqlite3_errmsg (plugin->dbh)); | ||
799 | return GNUNET_SYSERR; | ||
800 | } | ||
801 | if (GNUNET_OK != | ||
802 | GNUNET_SQ_exec_statements (plugin->dbh, | ||
803 | es)) | ||
804 | { | ||
805 | GNUNET_asprintf (emsg, | ||
806 | _ ("Failed to setup database with: `%s'\n"), | ||
807 | sqlite3_errmsg (plugin->dbh)); | ||
808 | return GNUNET_SYSERR; | ||
809 | } | ||
810 | return GNUNET_OK; | ||
811 | } | ||
812 | |||
813 | enum GNUNET_GenericReturnValue | ||
814 | namestore_sqlite_initialize_database (void *cls, char **emsg) | ||
815 | { | ||
816 | return init_database (cls, emsg, GNUNET_NO); | ||
817 | } | ||
818 | |||
819 | enum GNUNET_GenericReturnValue | ||
820 | namestore_sqlite_reset_database (void *cls, char **emsg) | ||
821 | { | ||
822 | return init_database (cls, emsg, GNUNET_YES); | ||
794 | } | 823 | } |
795 | 824 | ||
796 | /** | 825 | /** |
826 | * Initialize the database connections and associated | ||
827 | * data structures (create tables and indices | ||
828 | * as needed as well). | ||
829 | * | ||
830 | * @param plugin the plugin context (state for this module) | ||
831 | * @return #GNUNET_OK on success | ||
832 | */ | ||
833 | static int | ||
834 | database_connect (struct Plugin *plugin) | ||
835 | { | ||
836 | char *sqlite_filename; | ||
837 | char *emsg; | ||
838 | int try_create = GNUNET_NO; | ||
839 | |||
840 | if (GNUNET_OK != | ||
841 | GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, | ||
842 | "namestore-sqlite", | ||
843 | "FILENAME", | ||
844 | &sqlite_filename)) | ||
845 | { | ||
846 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
847 | "namestore-sqlite", | ||
848 | "FILENAME"); | ||
849 | return GNUNET_SYSERR; | ||
850 | } | ||
851 | if (GNUNET_OK != | ||
852 | GNUNET_DISK_file_test (sqlite_filename)) | ||
853 | { | ||
854 | if (GNUNET_OK != | ||
855 | GNUNET_DISK_directory_create_for_file (sqlite_filename)) | ||
856 | { | ||
857 | GNUNET_break (0); | ||
858 | GNUNET_free (sqlite_filename); | ||
859 | return GNUNET_SYSERR; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | /* Open database and precompile statements */ | ||
864 | if ((NULL == plugin->dbh) && | ||
865 | (SQLITE_OK != sqlite3_open (sqlite_filename, | ||
866 | &plugin->dbh))) | ||
867 | { | ||
868 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
869 | _ ("Unable to initialize SQLite: %s.\n"), | ||
870 | sqlite3_errmsg (plugin->dbh)); | ||
871 | GNUNET_free (sqlite_filename); | ||
872 | return GNUNET_SYSERR; | ||
873 | } | ||
874 | GNUNET_break (SQLITE_OK == | ||
875 | sqlite3_busy_timeout (plugin->dbh, | ||
876 | BUSY_TIMEOUT_MS)); | ||
877 | if (GNUNET_YES == | ||
878 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | ||
879 | "namestore-sqlite", | ||
880 | "INIT_ON_CONNECT")) | ||
881 | { | ||
882 | /** | ||
883 | * Gracefully fail as this should not be a critical error if the | ||
884 | * database is already created | ||
885 | */ | ||
886 | if (GNUNET_OK != init_database (plugin, &emsg, GNUNET_NO)) | ||
887 | { | ||
888 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
889 | "Failed to initialize database on connect: `%s'\n", | ||
890 | emsg); | ||
891 | GNUNET_free (emsg); | ||
892 | } | ||
893 | } | ||
894 | return GNUNET_OK; | ||
895 | } | ||
896 | |||
897 | |||
898 | /** | ||
797 | * Entry point for the plugin. | 899 | * Entry point for the plugin. |
798 | * | 900 | * |
799 | * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" | 901 | * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" |
@@ -808,9 +910,10 @@ libgnunet_plugin_namestore_sqlite_init (void *cls) | |||
808 | 910 | ||
809 | plugin = GNUNET_new (struct Plugin); | 911 | plugin = GNUNET_new (struct Plugin); |
810 | plugin->cfg = cfg; | 912 | plugin->cfg = cfg; |
811 | if (GNUNET_OK != database_setup (plugin)) | 913 | if (GNUNET_OK != database_connect (plugin)) |
812 | { | 914 | { |
813 | database_shutdown (plugin); | 915 | LOG (GNUNET_ERROR_TYPE_ERROR, |
916 | "Database could not be connected to.\n"); | ||
814 | GNUNET_free (plugin); | 917 | GNUNET_free (plugin); |
815 | return NULL; | 918 | return NULL; |
816 | } | 919 | } |
@@ -823,14 +926,16 @@ libgnunet_plugin_namestore_sqlite_init (void *cls) | |||
823 | api->transaction_begin = &namestore_sqlite_transaction_begin; | 926 | api->transaction_begin = &namestore_sqlite_transaction_begin; |
824 | api->transaction_commit = &namestore_sqlite_transaction_commit; | 927 | api->transaction_commit = &namestore_sqlite_transaction_commit; |
825 | api->transaction_rollback = &namestore_sqlite_transaction_rollback; | 928 | api->transaction_rollback = &namestore_sqlite_transaction_rollback; |
929 | api->initialize_database = &namestore_sqlite_initialize_database; | ||
930 | api->reset_database = &namestore_sqlite_reset_database; | ||
826 | /** | 931 | /** |
827 | * NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is | 932 | * NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is |
828 | * just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently | 933 | * just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently |
829 | * implicitly ensures this API behaves as it should | 934 | * implicitly ensures this API behaves as it should |
830 | */ | 935 | */ |
831 | api->edit_records = &namestore_sqlite_lookup_records; | 936 | api->edit_records = &namestore_sqlite_lookup_records; |
832 | LOG (GNUNET_ERROR_TYPE_INFO, | 937 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
833 | _ ("Sqlite database running\n")); | 938 | _ ("SQlite database running\n")); |
834 | return api; | 939 | return api; |
835 | } | 940 | } |
836 | 941 | ||
@@ -852,7 +957,7 @@ libgnunet_plugin_namestore_sqlite_done (void *cls) | |||
852 | GNUNET_free (plugin); | 957 | GNUNET_free (plugin); |
853 | GNUNET_free (api); | 958 | GNUNET_free (api); |
854 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 959 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
855 | "sqlite plugin is finished\n"); | 960 | "SQlite plugin is finished\n"); |
856 | return NULL; | 961 | return NULL; |
857 | } | 962 | } |
858 | 963 | ||