aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_namestore_sqlite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/plugin_namestore_sqlite.c')
-rw-r--r--src/namestore/plugin_namestore_sqlite.c243
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 */
122static int 127static int
123database_setup (struct Plugin *plugin) 128database_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
760static enum GNUNET_GenericReturnValue
761init_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
813enum GNUNET_GenericReturnValue
814namestore_sqlite_initialize_database (void *cls, char **emsg)
815{
816 return init_database (cls, emsg, GNUNET_NO);
817}
818
819enum GNUNET_GenericReturnValue
820namestore_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 */
833static int
834database_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