diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-07-25 23:12:26 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-07-25 23:12:26 +0000 |
commit | 6ec2c6dc89a62810fe44696d7faaad9d837105cd (patch) | |
tree | c8c0380028555266b8aa968027b23d3177e81ffb | |
parent | c890b76cde9288a8d9f2faa3046fbb06341c8082 (diff) | |
download | gnunet-6ec2c6dc89a62810fe44696d7faaad9d837105cd.tar.gz gnunet-6ec2c6dc89a62810fe44696d7faaad9d837105cd.zip |
making plugin compile
-rw-r--r-- | src/datacache/datacache_api.c | 37 | ||||
-rw-r--r-- | src/datacache/plugin_datacache_sqlite.c | 823 | ||||
-rw-r--r-- | src/datacache/plugin_datacache_template.c | 16 | ||||
-rw-r--r-- | src/datacache/test_datacache_api.c | 19 |
4 files changed, 333 insertions, 562 deletions
diff --git a/src/datacache/datacache_api.c b/src/datacache/datacache_api.c index 1fe428b08..05dfb89e2 100644 --- a/src/datacache/datacache_api.c +++ b/src/datacache/datacache_api.c | |||
@@ -69,11 +69,16 @@ struct GNUNET_DATACACHE_Handle | |||
69 | * Name of the library (i.e. "gnunet_plugin_datacache_sqlite"). | 69 | * Name of the library (i.e. "gnunet_plugin_datacache_sqlite"). |
70 | */ | 70 | */ |
71 | char *lib_name; | 71 | char *lib_name; |
72 | |||
73 | /** | ||
74 | * Name for the bloom filter file. | ||
75 | */ | ||
76 | char *bloom_name; | ||
72 | 77 | ||
73 | /** | 78 | /** |
74 | * Environment provided to our plugin. | 79 | * Environment provided to our plugin. |
75 | */ | 80 | */ |
76 | struct GNUNET_DATASTORE_PluginEnvironment env; | 81 | struct GNUNET_DATACACHE_PluginEnvironment env; |
77 | 82 | ||
78 | /** | 83 | /** |
79 | * How much space is in use right now? | 84 | * How much space is in use right now? |
@@ -116,21 +121,22 @@ GNUNET_DATACACHE_create (struct GNUNET_SCHEDULER_Handle *sched, | |||
116 | struct GNUNET_CONFIGURATION_Handle *cfg, | 121 | struct GNUNET_CONFIGURATION_Handle *cfg, |
117 | const char *section) | 122 | const char *section) |
118 | { | 123 | { |
124 | int fd; | ||
119 | unsigned int bf_size; | 125 | unsigned int bf_size; |
126 | unsigned long long quota; | ||
120 | struct GNUNET_DATACACHE_Handle *ret; | 127 | struct GNUNET_DATACACHE_Handle *ret; |
121 | struct DatacachePlugin *ret; | ||
122 | char *libname; | 128 | char *libname; |
123 | char *name; | 129 | char *name; |
124 | 130 | ||
125 | if (GNUNET_OK != | 131 | if (GNUNET_OK != |
126 | GNUNET_CONFIGURATION_get_value_number (c, | 132 | GNUNET_CONFIGURATION_get_value_number (cfg, |
127 | section, "QUOTA", "a)) | 133 | section, "QUOTA", "a)) |
128 | { | 134 | { |
129 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 135 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
130 | _("No `%s' specified for `%s' in configuration!\n"), | 136 | _("No `%s' specified for `%s' in configuration!\n"), |
131 | "QUOTA", | 137 | "QUOTA", |
132 | section); | 138 | section); |
133 | return; | 139 | return NULL; |
134 | } | 140 | } |
135 | if (GNUNET_OK != | 141 | if (GNUNET_OK != |
136 | GNUNET_CONFIGURATION_get_value_string (cfg, | 142 | GNUNET_CONFIGURATION_get_value_string (cfg, |
@@ -146,16 +152,26 @@ GNUNET_DATACACHE_create (struct GNUNET_SCHEDULER_Handle *sched, | |||
146 | bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */ | 152 | bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */ |
147 | 153 | ||
148 | ret = GNUNET_malloc (sizeof(struct GNUNET_DATACACHE_Handle)); | 154 | ret = GNUNET_malloc (sizeof(struct GNUNET_DATACACHE_Handle)); |
149 | /* FIXME: create a temporary file for the bloomfilter to better | 155 | ret->bloom_name = GNUNET_strdup ("/tmp/datacachebloomXXXXXX"); |
150 | support deletions! */ | 156 | fd = mkstemp (ret->bloom_name); |
151 | ret->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */ | 157 | if (fd != -1) |
158 | { | ||
159 | ret->filter = GNUNET_CONTAINER_bloomfilter_load (ret->bloom_name, | ||
160 | quota / 1024, /* 8 bit per entry in DB, expect 1k entries */ | ||
161 | 5); | ||
162 | CLOSE (fd); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | ret->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, bf_size, 5); /* approx. 3% false positives at max use */ | ||
167 | } | ||
152 | ret->section = GNUNET_strdup (section); | 168 | ret->section = GNUNET_strdup (section); |
153 | ret->env.sched = s; | 169 | ret->env.sched = sched; |
154 | ret->env.cfg = cfg; | 170 | ret->env.cfg = cfg; |
155 | ret->env.delete_notify = &env_delete_notify; | 171 | ret->env.delete_notify = &env_delete_notify; |
156 | ret->env.section = ret->section; | 172 | ret->env.section = ret->section; |
157 | ret->env.cls = ret; | 173 | ret->env.cls = ret; |
158 | ret->env.delete_notify = &delete_notify; | 174 | ret->env.delete_notify = &env_delete_notify; |
159 | ret->env.quota = quota; | 175 | ret->env.quota = quota; |
160 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 176 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
161 | _("Loading `%s' datacache plugin\n"), name); | 177 | _("Loading `%s' datacache plugin\n"), name); |
@@ -187,6 +203,7 @@ void GNUNET_DATACACHE_destroy (struct GNUNET_DATACACHE_Handle *h) | |||
187 | GNUNET_free (h->lib_name); | 203 | GNUNET_free (h->lib_name); |
188 | GNUNET_free (h->short_name); | 204 | GNUNET_free (h->short_name); |
189 | GNUNET_free (h->section); | 205 | GNUNET_free (h->section); |
206 | GNUNET_free (h->bloom_name); | ||
190 | GNUNET_free (h); | 207 | GNUNET_free (h); |
191 | } | 208 | } |
192 | 209 | ||
@@ -221,7 +238,7 @@ GNUNET_DATACACHE_put (struct GNUNET_DATACACHE_Handle *h, | |||
221 | if (used == 0) | 238 | if (used == 0) |
222 | return GNUNET_SYSERR; | 239 | return GNUNET_SYSERR; |
223 | GNUNET_CONTAINER_bloomfilter_add (h->filter, key); | 240 | GNUNET_CONTAINER_bloomfilter_add (h->filter, key); |
224 | while (h->utilization + used > h->api.quota) | 241 | while (h->utilization + used > h->env.quota) |
225 | GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls)); | 242 | GNUNET_assert (GNUNET_OK == h->api->del (h->api->cls)); |
226 | h->utilization += used; | 243 | h->utilization += used; |
227 | return GNUNET_OK; | 244 | return GNUNET_OK; |
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c index e386b55de..800241126 100644 --- a/src/datacache/plugin_datacache_sqlite.c +++ b/src/datacache/plugin_datacache_sqlite.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet |
3 | (C) 2006, 2007, 2008 Christian Grothoff (and other contributing authors) | 3 | (C) 2006, 2009 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,64 +19,55 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file applications/dstore_sqlite/dstore.c | 22 | * @file datacache/plugin_datacache_sqlite.c |
23 | * @brief SQLite based implementation of the dstore service | 23 | * @brief sqlite for an implementation of a database backend for the datacache |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * @todo Indexes, statistics | ||
26 | * | ||
27 | * Database: SQLite | ||
28 | */ | 25 | */ |
29 | |||
30 | #include "platform.h" | 26 | #include "platform.h" |
31 | #include "gnunet_util.h" | 27 | #include "gnunet_util_lib.h" |
32 | #include "gnunet_dstore_service.h" | 28 | #include "plugin_datacache.h" |
33 | #include "gnunet_stats_service.h" | ||
34 | #include <sqlite3.h> | 29 | #include <sqlite3.h> |
35 | 30 | ||
36 | #define DEBUG_DSTORE GNUNET_NO | 31 | #define DEBUG_DATACACHE_SQLITE GNUNET_YES |
37 | |||
38 | /** | ||
39 | * Maximum size for an individual item. | ||
40 | */ | ||
41 | #define MAX_CONTENT_SIZE 65536 | ||
42 | 32 | ||
43 | /** | 33 | /** |
44 | * Bytes used | 34 | * How much overhead do we assume per entry in the |
35 | * datacache? | ||
45 | */ | 36 | */ |
46 | static unsigned long long payload; | 37 | #define OVERHEAD (sizeof(GNUNET_HashCode) + 32) |
47 | 38 | ||
48 | /** | 39 | /** |
49 | * Maximum bytes available | 40 | * Context for all functions in this plugin. |
50 | */ | 41 | */ |
51 | static unsigned long long quota; | 42 | struct Plugin |
52 | 43 | { | |
53 | /** | 44 | /** |
54 | * Filename of this database | 45 | * Our execution environment. |
55 | */ | 46 | */ |
56 | static char *fn; | 47 | struct GNUNET_DATACACHE_PluginEnvironment *env; |
57 | static char *fn_utf8; | 48 | |
49 | /** | ||
50 | * Handle to the sqlite database. | ||
51 | */ | ||
52 | sqlite3 *dbh; | ||
58 | 53 | ||
59 | static GNUNET_CoreAPIForPlugins *coreAPI; | 54 | /** |
55 | * Filename used for the DB. | ||
56 | */ | ||
57 | char *fn; | ||
58 | }; | ||
60 | 59 | ||
61 | static struct GNUNET_Mutex *lock; | ||
62 | 60 | ||
63 | /** | 61 | /** |
64 | * Statistics service. | 62 | * Log an error message at log-level 'level' that indicates |
63 | * a failure of the command 'cmd' on file 'filename' | ||
64 | * with the message given by strerror(errno). | ||
65 | */ | 65 | */ |
66 | static GNUNET_Stats_ServiceAPI *stats; | 66 | #define LOG_SQLITE(db, level, cmd) do { GNUNET_log(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0) |
67 | 67 | ||
68 | static unsigned int stat_dstore_size; | ||
69 | |||
70 | static unsigned int stat_dstore_quota; | ||
71 | |||
72 | /** | ||
73 | * Estimate of the per-entry overhead (including indices). | ||
74 | */ | ||
75 | #define OVERHEAD ((4*2+4*2+8*2+8*2+sizeof(GNUNET_HashCode)*5+32)) | ||
76 | 68 | ||
77 | struct GNUNET_BloomFilter *bloom; | 69 | #define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0) |
78 | 70 | ||
79 | static char *bloom_name; | ||
80 | 71 | ||
81 | /** | 72 | /** |
82 | * @brief Prepare a SQL statement | 73 | * @brief Prepare a SQL statement |
@@ -91,375 +82,75 @@ sq_prepare (sqlite3 * dbh, const char *zSql, /* SQL statement, UTF-8 encoded | |||
91 | strlen (zSql), ppStmt, (const char **) &dummy); | 82 | strlen (zSql), ppStmt, (const char **) &dummy); |
92 | } | 83 | } |
93 | 84 | ||
94 | #define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { GNUNET_GE_LOG(coreAPI->ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0) | ||
95 | |||
96 | /** | ||
97 | * Log an error message at log-level 'level' that indicates | ||
98 | * a failure of the command 'cmd' on file 'filename' | ||
99 | * with the message given by strerror(errno). | ||
100 | */ | ||
101 | #define LOG_SQLITE(db, level, cmd) do { GNUNET_GE_LOG(coreAPI->ectx, level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0) | ||
102 | |||
103 | static void | ||
104 | db_init (sqlite3 * dbh) | ||
105 | { | ||
106 | char *emsg; | ||
107 | |||
108 | SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY"); | ||
109 | SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF"); | ||
110 | SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF"); | ||
111 | SQLITE3_EXEC (dbh, "PRAGMA page_size=4092"); | ||
112 | SQLITE3_EXEC (dbh, | ||
113 | "CREATE TABLE ds080 (" | ||
114 | " size INTEGER NOT NULL DEFAULT 0," | ||
115 | " type INTEGER NOT NULL DEFAULT 0," | ||
116 | " puttime INTEGER NOT NULL DEFAULT 0," | ||
117 | " expire INTEGER NOT NULL DEFAULT 0," | ||
118 | " key BLOB NOT NULL DEFAULT ''," | ||
119 | " vhash BLOB NOT NULL DEFAULT ''," | ||
120 | " value BLOB NOT NULL DEFAULT '')"); | ||
121 | SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds080 (key,type,expire)"); | ||
122 | SQLITE3_EXEC (dbh, | ||
123 | "CREATE INDEX idx_allidx ON ds080 (key,vhash,type,size)"); | ||
124 | SQLITE3_EXEC (dbh, "CREATE INDEX idx_puttime ON ds080 (puttime)"); | ||
125 | } | ||
126 | |||
127 | static int | ||
128 | db_reset () | ||
129 | { | ||
130 | int fd; | ||
131 | sqlite3 *dbh; | ||
132 | char *tmpl; | ||
133 | const char *tmpdir; | ||
134 | |||
135 | if (fn != NULL) | ||
136 | { | ||
137 | UNLINK (fn); | ||
138 | GNUNET_free (fn); | ||
139 | GNUNET_free (fn_utf8); | ||
140 | } | ||
141 | payload = 0; | ||
142 | |||
143 | tmpdir = getenv ("TMPDIR"); | ||
144 | tmpdir = tmpdir ? tmpdir : "/tmp"; | ||
145 | |||
146 | #define TEMPLATE "/gnunet-dstoreXXXXXX" | ||
147 | tmpl = GNUNET_malloc (strlen (tmpdir) + sizeof (TEMPLATE) + 1); | ||
148 | strcpy (tmpl, tmpdir); | ||
149 | strcat (tmpl, TEMPLATE); | ||
150 | #undef TEMPLATE | ||
151 | |||
152 | #ifdef MINGW | ||
153 | fn = (char *) GNUNET_malloc (MAX_PATH + 1); | ||
154 | plibc_conv_to_win_path (tmpl, fn); | ||
155 | GNUNET_free (tmpl); | ||
156 | #else | ||
157 | fn = tmpl; | ||
158 | #endif | ||
159 | fd = mkstemp (fn); | ||
160 | if (fd == -1) | ||
161 | { | ||
162 | GNUNET_GE_BREAK (NULL, 0); | ||
163 | GNUNET_free (fn); | ||
164 | fn = NULL; | ||
165 | return GNUNET_SYSERR; | ||
166 | } | ||
167 | CLOSE (fd); | ||
168 | fn_utf8 = GNUNET_convert_string_to_utf8 (coreAPI->ectx, fn, strlen (fn), | ||
169 | #ifdef ENABLE_NLS | ||
170 | nl_langinfo (CODESET) | ||
171 | #else | ||
172 | "UTF-8" /* good luck */ | ||
173 | #endif | ||
174 | ); | ||
175 | if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)) | ||
176 | { | ||
177 | GNUNET_free (fn); | ||
178 | GNUNET_free (fn_utf8); | ||
179 | fn = NULL; | ||
180 | return GNUNET_SYSERR; | ||
181 | } | ||
182 | db_init (dbh); | ||
183 | sqlite3_close (dbh); | ||
184 | return GNUNET_OK; | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * Check that we are within quota. | ||
189 | * @return GNUNET_OK if we are. | ||
190 | */ | ||
191 | static int | ||
192 | checkQuota (sqlite3 * dbh) | ||
193 | { | ||
194 | GNUNET_HashCode dkey; | ||
195 | GNUNET_HashCode vhash; | ||
196 | unsigned int dsize; | ||
197 | unsigned int dtype; | ||
198 | sqlite3_stmt *stmt; | ||
199 | sqlite3_stmt *dstmt; | ||
200 | int err; | ||
201 | |||
202 | if (payload * 10 <= quota * 9) | ||
203 | return GNUNET_OK; /* we seem to be about 10% off */ | ||
204 | #if DEBUG_DSTORE | ||
205 | GNUNET_GE_LOG (coreAPI->ectx, | ||
206 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, | ||
207 | "DStore above qutoa (have %llu, allowed %llu), will delete some data.\n", | ||
208 | payload, quota); | ||
209 | #endif | ||
210 | stmt = NULL; | ||
211 | dstmt = NULL; | ||
212 | if ((sq_prepare (dbh, | ||
213 | "SELECT size, type, key, vhash FROM ds080 ORDER BY puttime ASC LIMIT 1", | ||
214 | &stmt) != SQLITE_OK) || | ||
215 | (sq_prepare (dbh, | ||
216 | "DELETE FROM ds080 " | ||
217 | "WHERE key=? AND vhash=? AND type=? AND size=?", | ||
218 | &dstmt) != SQLITE_OK)) | ||
219 | { | ||
220 | GNUNET_GE_LOG (coreAPI->ectx, | ||
221 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | ||
222 | _("`%s' failed at %s:%d with error: %s\n"), | ||
223 | "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh)); | ||
224 | GNUNET_GE_BREAK (NULL, 0); | ||
225 | if (dstmt != NULL) | ||
226 | sqlite3_finalize (dstmt); | ||
227 | if (stmt != NULL) | ||
228 | sqlite3_finalize (stmt); | ||
229 | return GNUNET_SYSERR; | ||
230 | } | ||
231 | err = SQLITE_DONE; | ||
232 | while ((payload * 10 > quota * 9) && /* we seem to be about 10% off */ | ||
233 | ((err = sqlite3_step (stmt)) == SQLITE_ROW)) | ||
234 | { | ||
235 | dsize = sqlite3_column_int (stmt, 0); | ||
236 | dtype = sqlite3_column_int (stmt, 1); | ||
237 | GNUNET_GE_BREAK (NULL, | ||
238 | sqlite3_column_bytes (stmt, | ||
239 | 2) == sizeof (GNUNET_HashCode)); | ||
240 | GNUNET_GE_BREAK (NULL, | ||
241 | sqlite3_column_bytes (stmt, | ||
242 | 3) == sizeof (GNUNET_HashCode)); | ||
243 | memcpy (&dkey, sqlite3_column_blob (stmt, 2), sizeof (GNUNET_HashCode)); | ||
244 | memcpy (&vhash, sqlite3_column_blob (stmt, 3), | ||
245 | sizeof (GNUNET_HashCode)); | ||
246 | sqlite3_reset (stmt); | ||
247 | sqlite3_bind_blob (dstmt, | ||
248 | 1, &dkey, sizeof (GNUNET_HashCode), | ||
249 | SQLITE_TRANSIENT); | ||
250 | sqlite3_bind_blob (dstmt, | ||
251 | 2, &vhash, sizeof (GNUNET_HashCode), | ||
252 | SQLITE_TRANSIENT); | ||
253 | sqlite3_bind_int (dstmt, 3, dtype); | ||
254 | sqlite3_bind_int (dstmt, 4, dsize); | ||
255 | if ((err = sqlite3_step (dstmt)) != SQLITE_DONE) | ||
256 | { | ||
257 | GNUNET_GE_LOG (coreAPI->ectx, | ||
258 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | ||
259 | _("`%s' failed at %s:%d with error: %s\n"), | ||
260 | "sqlite3_step", __FILE__, __LINE__, | ||
261 | sqlite3_errmsg (dbh)); | ||
262 | sqlite3_reset (dstmt); | ||
263 | GNUNET_GE_BREAK (NULL, 0); /* should delete but cannot!? */ | ||
264 | break; | ||
265 | } | ||
266 | if (sqlite3_total_changes (dbh) > 0) | ||
267 | { | ||
268 | if (bloom != NULL) | ||
269 | GNUNET_bloomfilter_remove (bloom, &dkey); | ||
270 | payload -= (dsize + OVERHEAD); | ||
271 | } | ||
272 | #if DEBUG_DSTORE | ||
273 | GNUNET_GE_LOG (coreAPI->ectx, | ||
274 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | | ||
275 | GNUNET_GE_DEVELOPER, | ||
276 | "Deleting %u bytes decreases DStore payload to %llu out of %llu\n", | ||
277 | dsize, payload, quota); | ||
278 | #endif | ||
279 | sqlite3_reset (dstmt); | ||
280 | } | ||
281 | if (err != SQLITE_DONE) | ||
282 | { | ||
283 | GNUNET_GE_LOG (coreAPI->ectx, | ||
284 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | ||
285 | _("`%s' failed at %s:%d with error: %s\n"), | ||
286 | "sqlite3_step", __FILE__, __LINE__, | ||
287 | sqlite3_errmsg (dbh)); | ||
288 | } | ||
289 | sqlite3_finalize (dstmt); | ||
290 | sqlite3_finalize (stmt); | ||
291 | if (payload * 10 > quota * 9) | ||
292 | { | ||
293 | /* we seem to be about 10% off */ | ||
294 | GNUNET_GE_LOG (coreAPI->ectx, | ||
295 | GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_DEVELOPER, | ||
296 | "Failed to delete content to drop below quota (bug?).\n", | ||
297 | payload, quota); | ||
298 | return GNUNET_SYSERR; | ||
299 | } | ||
300 | return GNUNET_OK; | ||
301 | } | ||
302 | 85 | ||
303 | /** | 86 | /** |
304 | * Store an item in the datastore. | 87 | * Store an item in the datastore. |
305 | * | 88 | * |
306 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | 89 | * @param key key to store data under |
90 | * @param size number of bytes in data | ||
91 | * @param data data to store | ||
92 | * @param type type of the value | ||
93 | * @param discard_time when to discard the value in any case | ||
94 | * @return 0 on error, number of bytes used otherwise | ||
307 | */ | 95 | */ |
308 | static int | 96 | static uint32_t |
309 | d_put (const GNUNET_HashCode * key, | 97 | sqlite_plugin_put (void *cls, |
310 | unsigned int type, | 98 | const GNUNET_HashCode * key, |
311 | GNUNET_CronTime discard_time, unsigned int size, const char *data) | 99 | uint32_t size, |
100 | const char *data, | ||
101 | uint32_t type, | ||
102 | struct GNUNET_TIME_Absolute discard_time) | ||
312 | { | 103 | { |
313 | GNUNET_HashCode vhash; | 104 | struct Plugin *plugin = cls; |
314 | sqlite3 *dbh; | ||
315 | sqlite3_stmt *stmt; | 105 | sqlite3_stmt *stmt; |
316 | int ret; | ||
317 | GNUNET_CronTime now; | ||
318 | |||
319 | if (size > MAX_CONTENT_SIZE) | ||
320 | return GNUNET_SYSERR; | ||
321 | GNUNET_hash (data, size, &vhash); | ||
322 | GNUNET_mutex_lock (lock); | ||
323 | if ((fn == NULL) || (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))) | ||
324 | { | ||
325 | db_reset (dbh); | ||
326 | GNUNET_mutex_unlock (lock); | ||
327 | return GNUNET_SYSERR; | ||
328 | } | ||
329 | now = GNUNET_get_time (); | ||
330 | #if DEBUG_DSTORE | ||
331 | GNUNET_GE_LOG (coreAPI->ectx, | ||
332 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, | ||
333 | "dstore processes put `%.*s' with expiration %llu\n", | ||
334 | size, data, discard_time); | ||
335 | #endif | ||
336 | 106 | ||
337 | /* first try UPDATE */ | 107 | #if DEBUG_DATACACHE_SQLITE |
338 | if (sq_prepare (dbh, | 108 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
339 | "UPDATE ds080 SET puttime=?, expire=? " | 109 | "Processing `%s' of %u bytes with key `%4s' and expiration %llums\n", |
340 | "WHERE key=? AND vhash=? AND type=? AND size=?", | 110 | "PUT", |
341 | &stmt) != SQLITE_OK) | 111 | (unsigned int) size, |
112 | GNUNET_h2s (key), | ||
113 | (unsigned long long) GNUNET_TIME_absolute_get_remaining (discard_time).value); | ||
114 | #endif | ||
115 | if (sq_prepare (plugin->dbh, | ||
116 | "INSERT INTO ds090 " | ||
117 | "(type, expire, key, value) " | ||
118 | "VALUES (?, ?, ?, ?)", &stmt) != SQLITE_OK) | ||
342 | { | 119 | { |
343 | GNUNET_GE_LOG (coreAPI->ectx, | 120 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
344 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | 121 | _("`%s' failed at %s:%d with error: %s\n"), |
345 | _("`%s' failed at %s:%d with error: %s\n"), | 122 | "sq_prepare", __FILE__, __LINE__, |
346 | "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh)); | 123 | sqlite3_errmsg (plugin->dbh)); |
347 | sqlite3_close (dbh); | 124 | return 0; |
348 | GNUNET_mutex_unlock (lock); | ||
349 | return GNUNET_SYSERR; | ||
350 | } | 125 | } |
351 | if ((SQLITE_OK != | 126 | if ( (SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) || |
352 | sqlite3_bind_int64 (stmt, 1, now)) || | 127 | (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, discard_time.value)) || |
353 | (SQLITE_OK != | 128 | (SQLITE_OK != sqlite3_bind_blob (stmt, 3, key, sizeof (GNUNET_HashCode), |
354 | sqlite3_bind_int64 (stmt, 2, discard_time)) || | 129 | SQLITE_TRANSIENT)) || |
355 | (SQLITE_OK != | 130 | (SQLITE_OK != sqlite3_bind_blob (stmt, 4, data, size, SQLITE_TRANSIENT))) |
356 | sqlite3_bind_blob (stmt, 3, key, sizeof (GNUNET_HashCode), | ||
357 | SQLITE_TRANSIENT)) || | ||
358 | (SQLITE_OK != | ||
359 | sqlite3_bind_blob (stmt, 4, &vhash, sizeof (GNUNET_HashCode), | ||
360 | SQLITE_TRANSIENT)) || | ||
361 | (SQLITE_OK != sqlite3_bind_int (stmt, 5, type)) || | ||
362 | (SQLITE_OK != sqlite3_bind_int (stmt, 6, size))) | ||
363 | { | 131 | { |
364 | GNUNET_GE_LOG (coreAPI->ectx, | 132 | LOG_SQLITE (plugin->dbh, |
365 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | 133 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
366 | _("`%s' failed at %s:%d with error: %s\n"), | 134 | "sqlite3_bind_xxx"); |
367 | "sqlite3_bind_xxx", __FILE__, __LINE__, | ||
368 | sqlite3_errmsg (dbh)); | ||
369 | sqlite3_finalize (stmt); | 135 | sqlite3_finalize (stmt); |
370 | sqlite3_close (dbh); | 136 | return 0; |
371 | GNUNET_mutex_unlock (lock); | ||
372 | return GNUNET_SYSERR; | ||
373 | } | 137 | } |
374 | if (SQLITE_DONE != sqlite3_step (stmt)) | 138 | if (SQLITE_DONE != sqlite3_step (stmt)) |
375 | { | 139 | { |
376 | GNUNET_GE_LOG (coreAPI->ectx, | 140 | LOG_SQLITE (plugin->dbh, |
377 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | 141 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
378 | _("`%s' failed at %s:%d with error: %s\n"), | 142 | "sqlite3_step"); |
379 | "sqlite3_step", __FILE__, __LINE__, | ||
380 | sqlite3_errmsg (dbh)); | ||
381 | sqlite3_finalize (stmt); | 143 | sqlite3_finalize (stmt); |
382 | sqlite3_close (dbh); | 144 | return 0; |
383 | GNUNET_mutex_unlock (lock); | ||
384 | return GNUNET_SYSERR; | ||
385 | } | ||
386 | ret = sqlite3_changes (dbh); | ||
387 | sqlite3_finalize (stmt); | ||
388 | if (ret > 0) | ||
389 | { | ||
390 | sqlite3_close (dbh); | ||
391 | GNUNET_mutex_unlock (lock); | ||
392 | return GNUNET_OK; | ||
393 | } | ||
394 | if (GNUNET_OK != checkQuota (dbh)) | ||
395 | { | ||
396 | sqlite3_close (dbh); | ||
397 | GNUNET_mutex_unlock (lock); | ||
398 | return GNUNET_SYSERR; | ||
399 | } | ||
400 | if (sq_prepare (dbh, | ||
401 | "INSERT INTO ds080 " | ||
402 | "(size, type, puttime, expire, key, vhash, value) " | ||
403 | "VALUES (?, ?, ?, ?, ?, ?, ?)", &stmt) != SQLITE_OK) | ||
404 | { | ||
405 | GNUNET_GE_LOG (coreAPI->ectx, | ||
406 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | ||
407 | _("`%s' failed at %s:%d with error: %s\n"), | ||
408 | "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh)); | ||
409 | sqlite3_close (dbh); | ||
410 | GNUNET_mutex_unlock (lock); | ||
411 | return GNUNET_SYSERR; | ||
412 | } | ||
413 | if ((SQLITE_OK == sqlite3_bind_int (stmt, 1, size)) && | ||
414 | (SQLITE_OK == sqlite3_bind_int (stmt, 2, type)) && | ||
415 | (SQLITE_OK == sqlite3_bind_int64 (stmt, 3, now)) && | ||
416 | (SQLITE_OK == sqlite3_bind_int64 (stmt, 4, discard_time)) && | ||
417 | (SQLITE_OK == | ||
418 | sqlite3_bind_blob (stmt, 5, key, sizeof (GNUNET_HashCode), | ||
419 | SQLITE_TRANSIENT)) && | ||
420 | (SQLITE_OK == | ||
421 | sqlite3_bind_blob (stmt, 6, &vhash, sizeof (GNUNET_HashCode), | ||
422 | SQLITE_TRANSIENT)) | ||
423 | && (SQLITE_OK == | ||
424 | sqlite3_bind_blob (stmt, 7, data, size, SQLITE_TRANSIENT))) | ||
425 | { | ||
426 | if (SQLITE_DONE != sqlite3_step (stmt)) | ||
427 | { | ||
428 | LOG_SQLITE (dbh, | ||
429 | GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN | ||
430 | | GNUNET_GE_BULK, "sqlite3_step"); | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | payload += size + OVERHEAD; | ||
435 | if (bloom != NULL) | ||
436 | GNUNET_bloomfilter_add (bloom, key); | ||
437 | } | ||
438 | if (SQLITE_OK != sqlite3_finalize (stmt)) | ||
439 | LOG_SQLITE (dbh, | ||
440 | GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN | | ||
441 | GNUNET_GE_BULK, "sqlite3_finalize"); | ||
442 | } | ||
443 | else | ||
444 | { | ||
445 | LOG_SQLITE (dbh, | ||
446 | GNUNET_GE_ERROR | GNUNET_GE_DEVELOPER | GNUNET_GE_ADMIN | | ||
447 | GNUNET_GE_BULK, "sqlite3_bind_xxx"); | ||
448 | } | 145 | } |
449 | #if DEBUG_DSTORE | 146 | if (SQLITE_OK != sqlite3_finalize (stmt)) |
450 | GNUNET_GE_LOG (coreAPI->ectx, | 147 | LOG_SQLITE (plugin->dbh, |
451 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, | 148 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
452 | "Storing %u bytes increases DStore payload to %llu out of %llu\n", | 149 | "sqlite3_finalize"); |
453 | size, payload, quota); | 150 | return size + OVERHEAD; |
454 | #endif | ||
455 | checkQuota (dbh); | ||
456 | sqlite3_close (dbh); | ||
457 | GNUNET_mutex_unlock (lock); | ||
458 | if (stats != NULL) | ||
459 | stats->set (stat_dstore_size, payload); | ||
460 | return GNUNET_OK; | ||
461 | } | 151 | } |
462 | 152 | ||
153 | |||
463 | /** | 154 | /** |
464 | * Iterate over the results for a particular key | 155 | * Iterate over the results for a particular key |
465 | * in the datastore. | 156 | * in the datastore. |
@@ -467,16 +158,18 @@ d_put (const GNUNET_HashCode * key, | |||
467 | * @param key | 158 | * @param key |
468 | * @param type entries of which type are relevant? | 159 | * @param type entries of which type are relevant? |
469 | * @param iter maybe NULL (to just count) | 160 | * @param iter maybe NULL (to just count) |
470 | * @return the number of results, GNUNET_SYSERR if the | 161 | * @return the number of results found |
471 | * iter is non-NULL and aborted the iteration | ||
472 | */ | 162 | */ |
473 | static int | 163 | static unsigned int |
474 | d_get (const GNUNET_HashCode * key, | 164 | sqlite_plugin_get (void *cls, |
475 | unsigned int type, GNUNET_ResultProcessor handler, void *closure) | 165 | const GNUNET_HashCode * key, |
166 | uint32_t type, | ||
167 | GNUNET_DATACACHE_Iterator iter, | ||
168 | void *iter_cls) | ||
476 | { | 169 | { |
477 | sqlite3 *dbh; | 170 | struct Plugin *plugin = cls; |
478 | sqlite3_stmt *stmt; | 171 | sqlite3_stmt *stmt; |
479 | GNUNET_CronTime now; | 172 | struct GNUNET_TIME_Absolute now; |
480 | unsigned int size; | 173 | unsigned int size; |
481 | const char *dat; | 174 | const char *dat; |
482 | unsigned int cnt; | 175 | unsigned int cnt; |
@@ -484,193 +177,261 @@ d_get (const GNUNET_HashCode * key, | |||
484 | unsigned int total; | 177 | unsigned int total; |
485 | char scratch[256]; | 178 | char scratch[256]; |
486 | 179 | ||
487 | GNUNET_mutex_lock (lock); | 180 | now = GNUNET_TIME_absolute_get (); |
488 | if ((bloom != NULL) && (GNUNET_NO == GNUNET_bloomfilter_test (bloom, key))) | 181 | |
489 | { | 182 | #if DEBUG_DATACACHE_SQLITE |
490 | GNUNET_mutex_unlock (lock); | 183 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
491 | return 0; | 184 | "Processing `%s' for key `%4s'\n", |
492 | } | 185 | "GET", |
493 | if ((fn == NULL) || (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))) | 186 | GNUNET_h2s (key)); |
494 | { | ||
495 | db_reset (dbh); | ||
496 | GNUNET_mutex_unlock (lock); | ||
497 | return GNUNET_SYSERR; | ||
498 | } | ||
499 | now = GNUNET_get_time (); | ||
500 | #if DEBUG_DSTORE | ||
501 | GNUNET_GE_LOG (coreAPI->ectx, | ||
502 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_DEVELOPER, | ||
503 | "dstore processes get at `%llu'\n", now); | ||
504 | #endif | 187 | #endif |
505 | if (sq_prepare (dbh, | 188 | if (sq_prepare (plugin->dbh, |
506 | "SELECT count(*) FROM ds080 WHERE key=? AND type=? AND expire >= ?", | 189 | "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?", |
507 | &stmt) != SQLITE_OK) | 190 | &stmt) != SQLITE_OK) |
508 | { | 191 | { |
509 | GNUNET_GE_LOG (coreAPI->ectx, | 192 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
510 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | 193 | _("`%s' failed at %s:%d with error: %s\n"), |
511 | _("`%s' failed at %s:%d with error: %s\n"), | 194 | "sq_prepare", __FILE__, __LINE__, |
512 | "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (dbh)); | 195 | sqlite3_errmsg (plugin->dbh)); |
513 | sqlite3_close (dbh); | 196 | return 0; |
514 | db_reset (dbh); | ||
515 | GNUNET_mutex_unlock (lock); | ||
516 | return GNUNET_SYSERR; | ||
517 | } | 197 | } |
518 | sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), | 198 | sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), |
519 | SQLITE_TRANSIENT); | 199 | SQLITE_TRANSIENT); |
520 | sqlite3_bind_int (stmt, 2, type); | 200 | sqlite3_bind_int (stmt, 2, type); |
521 | sqlite3_bind_int64 (stmt, 3, now); | 201 | sqlite3_bind_int64 (stmt, 3, now.value); |
522 | if (SQLITE_ROW != sqlite3_step (stmt)) | 202 | if (SQLITE_ROW != sqlite3_step (stmt)) |
523 | { | 203 | { |
524 | LOG_SQLITE (dbh, | 204 | LOG_SQLITE (plugin->dbh, |
525 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER | | 205 | GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
526 | GNUNET_GE_BULK, "sqlite_step"); | 206 | "sqlite_step"); |
527 | sqlite3_reset (stmt); | ||
528 | sqlite3_finalize (stmt); | 207 | sqlite3_finalize (stmt); |
529 | db_reset (dbh); | 208 | return 0; |
530 | GNUNET_mutex_unlock (lock); | ||
531 | return GNUNET_SYSERR; | ||
532 | } | 209 | } |
533 | total = sqlite3_column_int (stmt, 0); | 210 | total = sqlite3_column_int (stmt, 0); |
534 | sqlite3_reset (stmt); | ||
535 | sqlite3_finalize (stmt); | 211 | sqlite3_finalize (stmt); |
536 | if ((total == 0) || (handler == NULL)) | 212 | if ( (total == 0) || (iter == NULL) ) |
537 | { | 213 | return total; |
538 | sqlite3_close (dbh); | ||
539 | GNUNET_mutex_unlock (lock); | ||
540 | return total; | ||
541 | } | ||
542 | 214 | ||
543 | cnt = 0; | 215 | cnt = 0; |
544 | off = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, total); | 216 | off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total); |
545 | while (cnt < total) | 217 | while (cnt < total) |
546 | { | 218 | { |
547 | off = (off + 1) % total; | 219 | off = (off + 1) % total; |
548 | GNUNET_snprintf (scratch, 256, | 220 | GNUNET_snprintf (scratch, |
549 | "SELECT size, value FROM ds080 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", | 221 | sizeof(scratch), |
222 | "SELECT value FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u", | ||
550 | off); | 223 | off); |
551 | if (sq_prepare (dbh, scratch, &stmt) != SQLITE_OK) | 224 | if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK) |
552 | { | 225 | { |
553 | GNUNET_GE_LOG (coreAPI->ectx, | 226 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
554 | GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, | 227 | _("`%s' failed at %s:%d with error: %s\n"), |
555 | _("`%s' failed at %s:%d with error: %s\n"), | 228 | "sq_prepare", __FILE__, __LINE__, |
556 | "sq_prepare", __FILE__, __LINE__, | 229 | sqlite3_errmsg (plugin->dbh)); |
557 | sqlite3_errmsg (dbh)); | 230 | return cnt; |
558 | sqlite3_close (dbh); | ||
559 | GNUNET_mutex_unlock (lock); | ||
560 | return GNUNET_SYSERR; | ||
561 | } | 231 | } |
562 | sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), | 232 | sqlite3_bind_blob (stmt, 1, key, sizeof (GNUNET_HashCode), |
563 | SQLITE_TRANSIENT); | 233 | SQLITE_TRANSIENT); |
564 | sqlite3_bind_int (stmt, 2, type); | 234 | sqlite3_bind_int (stmt, 2, type); |
565 | sqlite3_bind_int64 (stmt, 3, now); | 235 | sqlite3_bind_int64 (stmt, 3, now.value); |
566 | if (sqlite3_step (stmt) != SQLITE_ROW) | 236 | if (sqlite3_step (stmt) != SQLITE_ROW) |
567 | break; | 237 | break; |
568 | size = sqlite3_column_int (stmt, 0); | 238 | size = sqlite3_column_bytes (stmt, 0); |
569 | if (size != sqlite3_column_bytes (stmt, 1)) | ||
570 | { | ||
571 | GNUNET_GE_BREAK (NULL, 0); | ||
572 | sqlite3_finalize (stmt); | ||
573 | continue; | ||
574 | } | ||
575 | dat = sqlite3_column_blob (stmt, 1); | 239 | dat = sqlite3_column_blob (stmt, 1); |
576 | cnt++; | 240 | cnt++; |
577 | #if DEBUG_DSTORE | 241 | if (GNUNET_OK != iter (iter_cls, |
578 | GNUNET_GE_LOG (coreAPI->ectx, | 242 | key, |
579 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | | 243 | size, |
580 | GNUNET_GE_DEVELOPER, | 244 | dat, |
581 | "dstore found result for get: `%.*s'\n", size, dat); | 245 | type)) |
582 | #endif | ||
583 | if ((handler != NULL) && | ||
584 | (GNUNET_OK != handler (key, type, size, dat, closure))) | ||
585 | { | 246 | { |
586 | sqlite3_finalize (stmt); | 247 | sqlite3_finalize (stmt); |
587 | break; | 248 | break; |
588 | } | 249 | } |
589 | sqlite3_finalize (stmt); | 250 | sqlite3_finalize (stmt); |
590 | } | 251 | } |
591 | sqlite3_close (dbh); | ||
592 | GNUNET_mutex_unlock (lock); | ||
593 | return cnt; | 252 | return cnt; |
594 | } | 253 | } |
595 | 254 | ||
596 | GNUNET_Dstore_ServiceAPI * | 255 | |
597 | provide_module_dstore_sqlite (GNUNET_CoreAPIForPlugins * capi) | 256 | /** |
257 | * Delete the entry with the lowest expiration value | ||
258 | * from the datacache right now. | ||
259 | * | ||
260 | * @return GNUNET_OK on success, GNUNET_SYSERR on error | ||
261 | */ | ||
262 | static int | ||
263 | sqlite_plugin_del (void *cls) | ||
598 | { | 264 | { |
599 | static GNUNET_Dstore_ServiceAPI api; | 265 | struct Plugin *plugin = cls; |
600 | int fd; | 266 | unsigned int dsize; |
267 | unsigned int dtype; | ||
268 | sqlite3_stmt *stmt; | ||
269 | sqlite3_stmt *dstmt; | ||
601 | 270 | ||
602 | #if DEBUG_SQLITE | 271 | #if DEBUG_DATACACHE_SQLITE |
603 | GNUNET_GE_LOG (capi->ectx, | 272 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
604 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, | 273 | "Processing `%s'\n", |
605 | "SQLite Dstore: initializing database\n"); | 274 | "DEL"); |
606 | #endif | 275 | #endif |
607 | coreAPI = capi; | 276 | stmt = NULL; |
608 | if (GNUNET_OK != db_reset ()) | 277 | dstmt = NULL; |
278 | if ((sq_prepare (plugin->dbh, | ||
279 | "SELECT type, key, value FROM ds090 ORDER BY expire ASC LIMIT 1", | ||
280 | &stmt) != SQLITE_OK) || | ||
281 | (sq_prepare (plugin->dbh, | ||
282 | "DELETE FROM ds080 " | ||
283 | "WHERE key=? AND value=? AND type=?", | ||
284 | &dstmt) != SQLITE_OK)) | ||
609 | { | 285 | { |
610 | GNUNET_GE_BREAK (capi->ectx, 0); | 286 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
611 | return NULL; | 287 | _("`%s' failed at %s:%d with error: %s\n"), |
288 | "sq_prepare", __FILE__, __LINE__, sqlite3_errmsg (plugin->dbh)); | ||
289 | if (dstmt != NULL) | ||
290 | sqlite3_finalize (dstmt); | ||
291 | if (stmt != NULL) | ||
292 | sqlite3_finalize (stmt); | ||
293 | return GNUNET_SYSERR; | ||
612 | } | 294 | } |
613 | lock = GNUNET_mutex_create (GNUNET_NO); | 295 | if (SQLITE_ROW != sqlite3_step (stmt)) |
614 | |||
615 | |||
616 | api.get = &d_get; | ||
617 | api.put = &d_put; | ||
618 | GNUNET_GC_get_configuration_value_number (coreAPI->cfg, | ||
619 | "DSTORE", "QUOTA", 1, 1024, 1, | ||
620 | "a); | ||
621 | if (quota == 0) /* error */ | ||
622 | quota = 1; | ||
623 | quota *= 1024 * 1024; | ||
624 | |||
625 | bloom_name = GNUNET_strdup ("/tmp/dbloomXXXXXX"); | ||
626 | fd = mkstemp (bloom_name); | ||
627 | if (fd != -1) | ||
628 | { | 296 | { |
629 | bloom = GNUNET_bloomfilter_load (coreAPI->ectx, bloom_name, quota / (OVERHEAD + 1024), /* 8 bit per entry in DB, expect 1k entries */ | 297 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
630 | 5); | 298 | _("`%s' failed at %s:%d with error: %s\n"), |
631 | CLOSE (fd); | 299 | "sqlite3_step", __FILE__, __LINE__, |
300 | sqlite3_errmsg (plugin->dbh)); | ||
301 | sqlite3_finalize (dstmt); | ||
302 | sqlite3_finalize (stmt); | ||
303 | return GNUNET_SYSERR; | ||
632 | } | 304 | } |
633 | stats = capi->service_request ("stats"); | 305 | dtype = sqlite3_column_int (stmt, 0); |
634 | if (stats != NULL) | 306 | GNUNET_break (sqlite3_column_bytes (stmt, 1) == sizeof (GNUNET_HashCode)); |
307 | dsize = sqlite3_column_bytes (stmt, 2); | ||
308 | sqlite3_bind_blob (dstmt, | ||
309 | 1, sqlite3_column_blob (stmt, 1), | ||
310 | sizeof (GNUNET_HashCode), | ||
311 | SQLITE_TRANSIENT); | ||
312 | sqlite3_bind_blob (dstmt, | ||
313 | 2, sqlite3_column_blob (stmt, 2), | ||
314 | dsize, | ||
315 | SQLITE_TRANSIENT); | ||
316 | sqlite3_bind_int (dstmt, 3, dtype); | ||
317 | if (sqlite3_step (dstmt) != SQLITE_DONE) | ||
635 | { | 318 | { |
636 | stat_dstore_size = stats->create (gettext_noop ("# bytes in dstore")); | 319 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, |
637 | stat_dstore_quota = | 320 | _("`%s' failed at %s:%d with error: %s\n"), |
638 | stats->create (gettext_noop ("# max bytes allowed in dstore")); | 321 | "sqlite3_step", __FILE__, __LINE__, |
639 | stats->set (stat_dstore_quota, quota); | 322 | sqlite3_errmsg (plugin->dbh)); |
323 | sqlite3_finalize (dstmt); | ||
324 | sqlite3_finalize (stmt); | ||
325 | return GNUNET_SYSERR; | ||
640 | } | 326 | } |
641 | return &api; | 327 | plugin->env->delete_notify (plugin->env->cls, |
328 | sqlite3_column_blob (stmt, 1), | ||
329 | dsize + OVERHEAD); | ||
330 | sqlite3_finalize (dstmt); | ||
331 | sqlite3_finalize (stmt); | ||
332 | return GNUNET_OK; | ||
642 | } | 333 | } |
643 | 334 | ||
335 | |||
644 | /** | 336 | /** |
645 | * Shutdown the module. | 337 | * Entry point for the plugin. |
646 | */ | 338 | */ |
647 | void | 339 | void * |
648 | release_module_dstore_sqlite () | 340 | libgnunet_plugin_datacache_sqlite_init (void *cls) |
649 | { | 341 | { |
650 | UNLINK (fn); | 342 | struct GNUNET_DATACACHE_PluginEnvironment *env = cls; |
651 | GNUNET_free (fn); | 343 | struct GNUNET_DATACACHE_PluginFunctions *api; |
652 | GNUNET_free (fn_utf8); | 344 | struct Plugin *plugin; |
653 | fn = NULL; | 345 | char *fn; |
654 | if (bloom != NULL) | 346 | char *fn_utf8; |
347 | int fd; | ||
348 | sqlite3 *dbh; | ||
349 | char *tmpl; | ||
350 | const char *tmpdir; | ||
351 | char *emsg; | ||
352 | |||
353 | tmpdir = getenv ("TMPDIR"); | ||
354 | tmpdir = tmpdir ? tmpdir : "/tmp"; | ||
355 | |||
356 | #define TEMPLATE "/gnunet-dstoreXXXXXX" | ||
357 | tmpl = GNUNET_malloc (strlen (tmpdir) + sizeof (TEMPLATE) + 1); | ||
358 | strcpy (tmpl, tmpdir); | ||
359 | strcat (tmpl, TEMPLATE); | ||
360 | #undef TEMPLATE | ||
361 | #ifdef MINGW | ||
362 | fn = (char *) GNUNET_malloc (MAX_PATH + 1); | ||
363 | plibc_conv_to_win_path (tmpl, fn); | ||
364 | GNUNET_free (tmpl); | ||
365 | #else | ||
366 | fn = tmpl; | ||
367 | #endif | ||
368 | fd = mkstemp (fn); | ||
369 | if (fd == -1) | ||
655 | { | 370 | { |
656 | GNUNET_bloomfilter_free (bloom); | 371 | GNUNET_break (0); |
657 | bloom = NULL; | 372 | GNUNET_free (fn); |
373 | return NULL; | ||
658 | } | 374 | } |
659 | UNLINK (bloom_name); | 375 | CLOSE (fd); |
660 | GNUNET_free (bloom_name); | 376 | fn_utf8 = GNUNET_STRINGS_to_utf8 (fn, strlen (fn), |
661 | bloom_name = NULL; | 377 | #ifdef ENABLE_NLS |
662 | if (stats != NULL) | 378 | nl_langinfo (CODESET) |
379 | #else | ||
380 | "UTF-8" /* good luck */ | ||
381 | #endif | ||
382 | ); | ||
383 | if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh)) | ||
663 | { | 384 | { |
664 | coreAPI->service_release (stats); | 385 | GNUNET_free (fn); |
665 | stats = NULL; | 386 | GNUNET_free (fn_utf8); |
387 | return NULL; | ||
666 | } | 388 | } |
667 | #if DEBUG_SQLITE | 389 | GNUNET_free (fn); |
668 | GNUNET_GE_LOG (coreAPI->ectx, | 390 | |
669 | GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, | 391 | SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY"); |
670 | "SQLite Dstore: database shutdown\n"); | 392 | SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF"); |
671 | #endif | 393 | SQLITE3_EXEC (dbh, "PRAGMA count_changes=OFF"); |
672 | GNUNET_mutex_destroy (lock); | 394 | SQLITE3_EXEC (dbh, "PRAGMA page_size=4092"); |
673 | coreAPI = NULL; | 395 | SQLITE3_EXEC (dbh, |
396 | "CREATE TABLE ds090 (" | ||
397 | " type INTEGER NOT NULL DEFAULT 0," | ||
398 | " expire INTEGER NOT NULL DEFAULT 0," | ||
399 | " key BLOB NOT NULL DEFAULT ''," | ||
400 | " value BLOB NOT NULL DEFAULT '')"); | ||
401 | SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds080 (key,type,expire)"); | ||
402 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | ||
403 | plugin->env = env; | ||
404 | plugin->dbh = dbh; | ||
405 | plugin->fn = fn_utf8; | ||
406 | api = GNUNET_malloc (sizeof (struct GNUNET_DATACACHE_PluginFunctions)); | ||
407 | api->cls = plugin; | ||
408 | api->get = &sqlite_plugin_get; | ||
409 | api->put = &sqlite_plugin_put; | ||
410 | api->del = &sqlite_plugin_del; | ||
411 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
412 | "sqlite", _("Sqlite datacache running\n")); | ||
413 | return api; | ||
414 | } | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Exit point from the plugin. | ||
419 | */ | ||
420 | void * | ||
421 | libgnunet_plugin_datacache_sqlite_done (void *cls) | ||
422 | { | ||
423 | struct GNUNET_DATACACHE_PluginFunctions *api = cls; | ||
424 | struct Plugin *plugin = api->cls; | ||
425 | |||
426 | UNLINK (plugin->fn); | ||
427 | GNUNET_free (plugin->fn); | ||
428 | sqlite3_close (plugin->dbh); | ||
429 | GNUNET_free (plugin); | ||
430 | GNUNET_free (api); | ||
431 | return NULL; | ||
674 | } | 432 | } |
675 | 433 | ||
676 | /* end of dstore.c */ | 434 | |
435 | |||
436 | /* end of plugin_datacache_sqlite.c */ | ||
437 | |||
diff --git a/src/datacache/plugin_datacache_template.c b/src/datacache/plugin_datacache_template.c index d1f162c17..501284c30 100644 --- a/src/datacache/plugin_datacache_template.c +++ b/src/datacache/plugin_datacache_template.c | |||
@@ -23,20 +23,10 @@ | |||
23 | * @brief template for an implementation of a database backend for the datacache | 23 | * @brief template for an implementation of a database backend for the datacache |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | */ | 25 | */ |
26 | #ifndef PLUGIN_DATACACHE_H | 26 | #include "platform.h" |
27 | #define PLUGIN_DATACACHE_H | 27 | #include "gnunet_util_lib.h" |
28 | |||
29 | #include "plugin_datacache.h" | 28 | #include "plugin_datacache.h" |
30 | 29 | ||
31 | #ifdef __cplusplus | ||
32 | extern "C" | ||
33 | { | ||
34 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
35 | } | ||
36 | #endif | ||
37 | #endif | ||
38 | |||
39 | |||
40 | 30 | ||
41 | /** | 31 | /** |
42 | * Context for all functions in this plugin. | 32 | * Context for all functions in this plugin. |
@@ -46,7 +36,7 @@ struct Plugin | |||
46 | /** | 36 | /** |
47 | * Our execution environment. | 37 | * Our execution environment. |
48 | */ | 38 | */ |
49 | struct GNUNET_DATASTORE_PluginEnvironment *env; | 39 | struct GNUNET_DATACACHE_PluginEnvironment *env; |
50 | }; | 40 | }; |
51 | 41 | ||
52 | 42 | ||
diff --git a/src/datacache/test_datacache_api.c b/src/datacache/test_datacache_api.c index 00b63cda8..d4fea584f 100644 --- a/src/datacache/test_datacache_api.c +++ b/src/datacache/test_datacache_api.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2006 Christian Grothoff (and other contributing authors) | 3 | (C) 2006, 2009 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -18,17 +18,16 @@ | |||
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | /* | 20 | /* |
21 | * @file applications/dstore/dstore_test.c | 21 | * @file datacache/test_datacache_api.c |
22 | * @brief Test for the dstore implementations. | 22 | * @brief Test for the datacache implementations. |
23 | * @author Nils Durner | 23 | * @author Nils Durner |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet_util.h" | 27 | #include "gnunet_util_lib.h" |
28 | #include "gnunet_protocols.h" | 28 | #include "gnunet_datacache_lib.h" |
29 | #include "gnunet_dstore_service.h" | ||
30 | #include "core.h" | ||
31 | 29 | ||
30 | #if 0 | ||
32 | #define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) | 31 | #define ASSERT(x) do { if (! (x)) { printf("Error at %s:%d\n", __FILE__, __LINE__); goto FAILURE;} } while (0) |
33 | 32 | ||
34 | static int error; | 33 | static int error; |
@@ -85,10 +84,12 @@ FAILURE: | |||
85 | } | 84 | } |
86 | 85 | ||
87 | #define TEST_DB "/tmp/GNUnet_dstore_test/" | 86 | #define TEST_DB "/tmp/GNUnet_dstore_test/" |
87 | #endif | ||
88 | 88 | ||
89 | int | 89 | int |
90 | main (int argc, char *argv[]) | 90 | main (int argc, char *argv[]) |
91 | { | 91 | { |
92 | #if 0 | ||
92 | GNUNET_Dstore_ServiceAPI *api; | 93 | GNUNET_Dstore_ServiceAPI *api; |
93 | int ok; | 94 | int ok; |
94 | struct GNUNET_GC_Configuration *cfg; | 95 | struct GNUNET_GC_Configuration *cfg; |
@@ -115,6 +116,8 @@ main (int argc, char *argv[]) | |||
115 | if (ok == GNUNET_SYSERR) | 116 | if (ok == GNUNET_SYSERR) |
116 | return 1; | 117 | return 1; |
117 | return error; | 118 | return error; |
119 | #endif | ||
120 | return 0; | ||
118 | } | 121 | } |
119 | 122 | ||
120 | /* end of dstore_test.c */ | 123 | /* end of test_datacache_api.c */ |