diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/peerstore/Makefile.am | 14 | ||||
-rw-r--r-- | src/peerstore/peerstore.conf.in | 5 | ||||
-rw-r--r-- | src/peerstore/plugin_peerstore_file.c | 33 | ||||
-rw-r--r-- | src/peerstore/plugin_peerstore_sqlite.c | 270 |
4 files changed, 281 insertions, 41 deletions
diff --git a/src/peerstore/Makefile.am b/src/peerstore/Makefile.am index 821700b5a..40072836c 100644 --- a/src/peerstore/Makefile.am +++ b/src/peerstore/Makefile.am | |||
@@ -47,17 +47,17 @@ libgnunetpeerstore_la_LDFLAGS = \ | |||
47 | $(GNUNET_LDFLAGS) | 47 | $(GNUNET_LDFLAGS) |
48 | 48 | ||
49 | plugin_LTLIBRARIES = \ | 49 | plugin_LTLIBRARIES = \ |
50 | libgnunet_plugin_peerstore_file.la | 50 | libgnunet_plugin_peerstore_sqlite.la |
51 | 51 | ||
52 | libgnunet_plugin_peerstore_file_la_SOURCES = \ | 52 | libgnunet_plugin_peerstore_sqlite_la_SOURCES = \ |
53 | plugin_peerstore_file.c | 53 | plugin_peerstore_sqlite.c |
54 | libgnunet_plugin_peerstore_file_la_LIBADD = \ | 54 | libgnunet_plugin_peerstore_sqlite_la_LIBADD = \ |
55 | $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ | 55 | $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ |
56 | $(top_builddir)/src/util/libgnunetutil.la \ | 56 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ |
57 | $(LTLIBINTL) | 57 | $(LTLIBINTL) |
58 | libgnunet_plugin_peerstore_file_la_LDFLAGS = \ | 58 | libgnunet_plugin_peerstore_sqlite_la_LDFLAGS = \ |
59 | $(GN_PLUGIN_LDFLAGS) | 59 | $(GN_PLUGIN_LDFLAGS) |
60 | libgnunet_plugin_peerstore_file_la_DEPENDENCIES = \ | 60 | libgnunet_plugin_peerstore_sqlite_la_DEPENDENCIES = \ |
61 | $(top_builddir)/src/util/libgnunetutil.la \ | 61 | $(top_builddir)/src/util/libgnunetutil.la \ |
62 | libgnunetpeerstore.la | 62 | libgnunetpeerstore.la |
63 | 63 | ||
diff --git a/src/peerstore/peerstore.conf.in b/src/peerstore/peerstore.conf.in index 50e0f867f..ffdbc452f 100644 --- a/src/peerstore/peerstore.conf.in +++ b/src/peerstore/peerstore.conf.in | |||
@@ -4,5 +4,8 @@ UNIXPATH = /tmp/gnunet-service-peerstore.sock | |||
4 | HOME = $SERVICEHOME | 4 | HOME = $SERVICEHOME |
5 | # PORT = 2106 | 5 | # PORT = 2106 |
6 | @UNIXONLY@ PORT = 2088 | 6 | @UNIXONLY@ PORT = 2088 |
7 | DATABASE = file | 7 | DATABASE = sqlite |
8 | |||
9 | [peerstore-sqlite] | ||
10 | FILENAME = $GNUNET_DATA_HOME/peerstore/sqlite.db | ||
8 | 11 | ||
diff --git a/src/peerstore/plugin_peerstore_file.c b/src/peerstore/plugin_peerstore_file.c deleted file mode 100644 index b23088bc2..000000000 --- a/src/peerstore/plugin_peerstore_file.c +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * (C) 2013 Christian Grothoff (and other contributing authors) | ||
4 | * | ||
5 | * GNUnet is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published | ||
7 | * by the Free Software Foundation; either version 3, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * GNUnet is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with GNUnet; see the file COPYING. If not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file peerstore/plugin_peerstore_file.c | ||
23 | * @brief file-based peerstore backend | ||
24 | * @author Omar Tarabai | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_peerstore_plugin.h" | ||
29 | #include "gnunet_peerstore_service.h" | ||
30 | #include "peerstore.h" | ||
31 | |||
32 | |||
33 | /* end of plugin_peerstore_file.c */ | ||
diff --git a/src/peerstore/plugin_peerstore_sqlite.c b/src/peerstore/plugin_peerstore_sqlite.c new file mode 100644 index 000000000..ff6ae9f67 --- /dev/null +++ b/src/peerstore/plugin_peerstore_sqlite.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * (C) 2013 Christian Grothoff (and other contributing authors) | ||
4 | * | ||
5 | * GNUnet is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published | ||
7 | * by the Free Software Foundation; either version 3, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * GNUnet is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with GNUnet; see the file COPYING. If not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file peerstore/plugin_peerstore_sqlite.c | ||
23 | * @brief sqlite-based peerstore backend | ||
24 | * @author Omar Tarabai | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_peerstore_plugin.h" | ||
29 | #include "gnunet_peerstore_service.h" | ||
30 | #include "peerstore.h" | ||
31 | #include <sqlite3.h> | ||
32 | |||
33 | /** | ||
34 | * After how many ms "busy" should a DB operation fail for good? A | ||
35 | * low value makes sure that we are more responsive to requests | ||
36 | * (especially PUTs). A high value guarantees a higher success rate | ||
37 | * (SELECTs in iterate can take several seconds despite LIMIT=1). | ||
38 | * | ||
39 | * The default value of 1s should ensure that users do not experience | ||
40 | * huge latencies while at the same time allowing operations to | ||
41 | * succeed with reasonable probability. | ||
42 | */ | ||
43 | #define BUSY_TIMEOUT_MS 1000 | ||
44 | |||
45 | /** | ||
46 | * Log an error message at log-level 'level' that indicates | ||
47 | * a failure of the command 'cmd' on file 'filename' | ||
48 | * with the message given by strerror(errno). | ||
49 | */ | ||
50 | #define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "peerstore-sqlite", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) | ||
51 | |||
52 | #define LOG(kind,...) GNUNET_log_from (kind, "peerstore-sqlite", __VA_ARGS__) | ||
53 | |||
54 | /** | ||
55 | * Context for all functions in this plugin. | ||
56 | */ | ||
57 | struct Plugin | ||
58 | { | ||
59 | |||
60 | /** | ||
61 | * Configuration handle | ||
62 | */ | ||
63 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
64 | |||
65 | /** | ||
66 | * Database filename. | ||
67 | */ | ||
68 | char *fn; | ||
69 | |||
70 | /** | ||
71 | * Native SQLite database handle. | ||
72 | */ | ||
73 | sqlite3 *dbh; | ||
74 | |||
75 | /** | ||
76 | * Precompiled SQL for inserting into peerstoredata | ||
77 | */ | ||
78 | sqlite3_stmt *insert_peerstoredata; | ||
79 | |||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * @brief Prepare a SQL statement | ||
84 | * | ||
85 | * @param dbh handle to the database | ||
86 | * @param sql SQL statement, UTF-8 encoded | ||
87 | * @return 0 on success | ||
88 | */ | ||
89 | static int | ||
90 | sql_exec (sqlite3 *dbh, const char *sql) | ||
91 | { | ||
92 | int result; | ||
93 | |||
94 | result = sqlite3_exec (dbh, sql, NULL, NULL, NULL); | ||
95 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
96 | "Executed `%s' / %d\n", sql, result); | ||
97 | if (result != SQLITE_OK) | ||
98 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
99 | _("Error executing SQL query: %s\n %s\n"), | ||
100 | sqlite3_errmsg (dbh), sql); | ||
101 | return result; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * @brief Prepare a SQL statement | ||
106 | * | ||
107 | * @param dbh handle to the database | ||
108 | * @param sql SQL statement, UTF-8 encoded | ||
109 | * @param stmt set to the prepared statement | ||
110 | * @return 0 on success | ||
111 | */ | ||
112 | static int | ||
113 | sql_prepare (sqlite3 *dbh, const char *sql, sqlite3_stmt **stmt) | ||
114 | { | ||
115 | char *tail; | ||
116 | int result; | ||
117 | |||
118 | result = sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt, | ||
119 | (const char **) &tail); | ||
120 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
121 | "Prepared `%s' / %p: %d\n", sql, *stmt, result); | ||
122 | if (result != SQLITE_OK) | ||
123 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
124 | _("Error preparing SQL query: %s\n %s\n"), | ||
125 | sqlite3_errmsg (dbh), sql); | ||
126 | return result; | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * Initialize the database connections and associated | ||
131 | * data structures (create tables and indices | ||
132 | * as needed as well). | ||
133 | * | ||
134 | * @param plugin the plugin context (state for this module) | ||
135 | * @return GNUNET_OK on success | ||
136 | */ | ||
137 | static int | ||
138 | database_setup (struct Plugin *plugin) | ||
139 | { | ||
140 | char *filename; | ||
141 | |||
142 | if (GNUNET_OK != | ||
143 | GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "peerstore-sqlite", | ||
144 | "FILENAME", &filename)) | ||
145 | { | ||
146 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
147 | "peerstore-sqlite", "FILENAME"); | ||
148 | return GNUNET_SYSERR; | ||
149 | } | ||
150 | if (GNUNET_OK != GNUNET_DISK_file_test (filename)) | ||
151 | { | ||
152 | if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (filename)) | ||
153 | { | ||
154 | GNUNET_break (0); | ||
155 | GNUNET_free (filename); | ||
156 | return GNUNET_SYSERR; | ||
157 | } | ||
158 | } | ||
159 | /* filename should be UTF-8-encoded. If it isn't, it's a bug */ | ||
160 | plugin->fn = filename; | ||
161 | |||
162 | /* Open database and precompile statements */ | ||
163 | if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh)) | ||
164 | { | ||
165 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
166 | _("Unable to initialize SQLite: %s.\n"), | ||
167 | sqlite3_errmsg (plugin->dbh)); | ||
168 | return GNUNET_SYSERR; | ||
169 | } | ||
170 | |||
171 | sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY"); | ||
172 | sql_exec (plugin->dbh, "PRAGMA synchronous=NORMAL"); | ||
173 | sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF"); | ||
174 | sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL"); | ||
175 | sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\""); | ||
176 | sql_exec (plugin->dbh, "PRAGMA count_changes=OFF"); | ||
177 | sql_exec (plugin->dbh, "PRAGMA page_size=4096"); | ||
178 | |||
179 | sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS); | ||
180 | |||
181 | /* Create tables */ | ||
182 | |||
183 | sql_exec (plugin->dbh, | ||
184 | "CREATE TABLE IF NOT EXISTS peerstoredata (\n" | ||
185 | " sub_system TEXT NOT NULL,\n" | ||
186 | " peer_id BLOB NOT NULL,\n" | ||
187 | " value BLOB NULL" | ||
188 | ");"); | ||
189 | |||
190 | /* Prepare statements */ | ||
191 | |||
192 | sql_prepare (plugin->dbh, | ||
193 | "INSERT INTO peerstoredata (sub_system, peer_id, value) VALUES (?,?,?);", | ||
194 | &plugin->insert_peerstoredata); | ||
195 | |||
196 | return GNUNET_OK; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * Shutdown database connection and associate data | ||
201 | * structures. | ||
202 | * @param plugin the plugin context (state for this module) | ||
203 | */ | ||
204 | static void | ||
205 | database_shutdown (struct Plugin *plugin) | ||
206 | { | ||
207 | int result; | ||
208 | sqlite3_stmt *stmt; | ||
209 | while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL))) | ||
210 | { | ||
211 | result = sqlite3_finalize (stmt); | ||
212 | if (SQLITE_OK != result) | ||
213 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
214 | "Failed to close statement %p: %d\n", stmt, result); | ||
215 | } | ||
216 | if (SQLITE_OK != sqlite3_close (plugin->dbh)) | ||
217 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); | ||
218 | |||
219 | GNUNET_free_non_null (plugin->fn); | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * Entry point for the plugin. | ||
224 | * | ||
225 | * @param cls The struct GNUNET_CONFIGURATION_Handle. | ||
226 | * @return NULL on error, otherwise the plugin context | ||
227 | */ | ||
228 | void * | ||
229 | libgnunet_plugin_peerstore_sqlite_init (void *cls) | ||
230 | { | ||
231 | static struct Plugin plugin; | ||
232 | const struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
233 | struct GNUNET_PEERSTORE_PluginFunctions *api; | ||
234 | |||
235 | if (NULL != plugin.cfg) | ||
236 | return NULL; /* can only initialize once! */ | ||
237 | memset (&plugin, 0, sizeof (struct Plugin)); | ||
238 | plugin.cfg = cfg; | ||
239 | if (GNUNET_OK != database_setup (&plugin)) | ||
240 | { | ||
241 | database_shutdown (&plugin); | ||
242 | return NULL; | ||
243 | } | ||
244 | api = GNUNET_new (struct GNUNET_PEERSTORE_PluginFunctions); | ||
245 | api->cls = &plugin; | ||
246 | LOG(GNUNET_ERROR_TYPE_INFO, "Sqlite plugin is running\n"); | ||
247 | return api; | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * Exit point from the plugin. | ||
252 | * | ||
253 | * @param cls The plugin context (as returned by "init") | ||
254 | * @return Always NULL | ||
255 | */ | ||
256 | void * | ||
257 | libgnunet_plugin_peerstore_sqlite_done (void *cls) | ||
258 | { | ||
259 | struct GNUNET_PEERSTORE_PluginFunctions *api = cls; | ||
260 | struct Plugin *plugin = api->cls; | ||
261 | |||
262 | database_shutdown (plugin); | ||
263 | plugin->cfg = NULL; | ||
264 | GNUNET_free (api); | ||
265 | LOG (GNUNET_ERROR_TYPE_INFO, "Sqlite plugin is finished\n"); | ||
266 | return NULL; | ||
267 | |||
268 | } | ||
269 | |||
270 | /* end of plugin_peerstore_sqlite.c */ | ||