aboutsummaryrefslogtreecommitdiff
path: root/src/datastore
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-08-28 21:34:36 +0000
committerChristian Grothoff <christian@grothoff.org>2010-08-28 21:34:36 +0000
commit57924abe125fa52dce4dc2e84cb0a7c4dcd04579 (patch)
tree51420ad914e9ac3c0b7ab0974cf574afe4f5f715 /src/datastore
parent3cb045c1df8bda92f5b4f54b5f9bf4463096cac0 (diff)
downloadgnunet-57924abe125fa52dce4dc2e84cb0a7c4dcd04579.tar.gz
gnunet-57924abe125fa52dce4dc2e84cb0a7c4dcd04579.zip
train hacks
Diffstat (limited to 'src/datastore')
-rw-r--r--src/datastore/gnunet-service-datastore.c143
-rw-r--r--src/datastore/perf_plugin_datastore.c16
-rw-r--r--src/datastore/plugin_datastore.h28
-rw-r--r--src/datastore/plugin_datastore_mysql.c46
-rw-r--r--src/datastore/plugin_datastore_postgres.c158
-rw-r--r--src/datastore/plugin_datastore_sqlite.c230
6 files changed, 397 insertions, 224 deletions
diff --git a/src/datastore/gnunet-service-datastore.c b/src/datastore/gnunet-service-datastore.c
index 40ea153de..01778b1b7 100644
--- a/src/datastore/gnunet-service-datastore.c
+++ b/src/datastore/gnunet-service-datastore.c
@@ -42,6 +42,13 @@
42 */ 42 */
43#define MAX_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) 43#define MAX_EXPIRE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
44 44
45#define QUOTA_STAT_NAME gettext_noop ("# bytes used in file-sharing datastore")
46
47/**
48 * After how many payload-changing operations
49 * do we sync our statistics?
50 */
51#define MAX_STAT_SYNC_LAG 50
45 52
46 53
47/** 54/**
@@ -109,6 +116,7 @@ struct ReservationList
109}; 116};
110 117
111 118
119
112/** 120/**
113 * Our datastore plugin (NULL if not available). 121 * Our datastore plugin (NULL if not available).
114 */ 122 */
@@ -141,6 +149,24 @@ static unsigned long long cache_size;
141 * How much space have we currently reserved? 149 * How much space have we currently reserved?
142 */ 150 */
143static unsigned long long reserved; 151static unsigned long long reserved;
152
153/**
154 * How much data are we currently storing
155 * in the database?
156 */
157static unsigned long long payload;
158
159/**
160 * Number of updates that were made to the
161 * payload value since we last synchronized
162 * it with the statistics service.
163 */
164static unsigned int lastSync;
165
166/**
167 * Did we get an answer from statistics?
168 */
169static int stats_worked;
144 170
145/** 171/**
146 * Identity of the task that is used to delete 172 * Identity of the task that is used to delete
@@ -165,6 +191,23 @@ static struct GNUNET_STATISTICS_Handle *stats;
165 191
166 192
167/** 193/**
194 * Synchronize our utilization statistics with the
195 * statistics service.
196 */
197static void
198sync_stats ()
199{
200 GNUNET_STATISTICS_set (stats,
201 QUOTA_STAT_NAME,
202 payload,
203 GNUNET_YES);
204 lastSync = 0;
205}
206
207
208
209
210/**
168 * Function called once the transmit operation has 211 * Function called once the transmit operation has
169 * either failed or succeeded. 212 * either failed or succeeded.
170 * 213 *
@@ -242,6 +285,12 @@ static struct TransmitCallbackContext *tcc_tail;
242static int cleaning_done; 285static int cleaning_done;
243 286
244/** 287/**
288 * Handle for pending get request.
289 */
290static struct GNUNET_STATISTICS_GetHandle *stat_get;
291
292
293/**
245 * Task that is used to remove expired entries from 294 * Task that is used to remove expired entries from
246 * the datastore. This task will schedule itself 295 * the datastore. This task will schedule itself
247 * again automatically to always delete all expired 296 * again automatically to always delete all expired
@@ -731,7 +780,7 @@ handle_reserve (void *cls,
731#endif 780#endif
732 amount = GNUNET_ntohll(msg->amount); 781 amount = GNUNET_ntohll(msg->amount);
733 entries = ntohl(msg->entries); 782 entries = ntohl(msg->entries);
734 used = plugin->api->get_size (plugin->api->cls) + reserved; 783 used = payload + reserved;
735 req = amount + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * entries; 784 req = amount + ((unsigned long long) GNUNET_DATASTORE_ENTRY_OVERHEAD) * entries;
736 if (used + req > quota) 785 if (used + req > quota)
737 { 786 {
@@ -931,13 +980,13 @@ execute_put (struct GNUNET_SERVER_Client *client,
931 (GNUNET_SYSERR == ret) ? GNUNET_SYSERR : GNUNET_OK, 980 (GNUNET_SYSERR == ret) ? GNUNET_SYSERR : GNUNET_OK,
932 msg); 981 msg);
933 GNUNET_free_non_null (msg); 982 GNUNET_free_non_null (msg);
934 if (quota - reserved - cache_size < plugin->api->get_size (plugin->api->cls)) 983 if (quota - reserved - cache_size < payload)
935 { 984 {
936 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 985 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
937 _("Need %llu bytes more space (%llu allowed, using %llu)\n"), 986 _("Need %llu bytes more space (%llu allowed, using %llu)\n"),
938 (unsigned long long) size + GNUNET_DATASTORE_ENTRY_OVERHEAD, 987 (unsigned long long) size + GNUNET_DATASTORE_ENTRY_OVERHEAD,
939 (unsigned long long) (quota - reserved - cache_size), 988 (unsigned long long) (quota - reserved - cache_size),
940 (unsigned long long) plugin->api->get_size (plugin->api->cls)); 989 (unsigned long long) payload);
941 manage_space (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); 990 manage_space (size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
942 } 991 }
943} 992}
@@ -1351,6 +1400,78 @@ handle_drop (void *cls,
1351 1400
1352 1401
1353/** 1402/**
1403 * Function called by plugins to notify us about a
1404 * change in their disk utilization.
1405 *
1406 * @param cls closure (NULL)
1407 * @param delta change in disk utilization,
1408 * 0 for "reset to empty"
1409 */
1410static void
1411disk_utilization_change_cb (void *cls,
1412 int delta)
1413{
1414 if ( (delta < 0) &&
1415 (payload < -delta) )
1416 {
1417 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1418 _("Datastore payload inaccurate (%lld < %lld). Trying to fix.\n"),
1419 (long long) payload,
1420 (long long) -delta);
1421 payload = plugin->api->get_size (plugin->api->cls);
1422 sync_stats ();
1423 return;
1424 }
1425 payload += delta;
1426 lastSync++;
1427 if (lastSync >= MAX_STAT_SYNC_LAG)
1428 sync_stats ();
1429}
1430
1431
1432/**
1433 * Callback function to process statistic values.
1434 *
1435 * @param cls closure (struct Plugin*)
1436 * @param subsystem name of subsystem that created the statistic
1437 * @param name the name of the datum
1438 * @param value the current value
1439 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
1440 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
1441 */
1442static int
1443process_stat_in (void *cls,
1444 const char *subsystem,
1445 const char *name,
1446 uint64_t value,
1447 int is_persistent)
1448{
1449 GNUNET_assert (stats_worked == GNUNET_NO);
1450 stats_worked = GNUNET_YES;
1451 payload += value;
1452#if DEBUG_SQLITE
1453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1454 "Notification from statistics about existing payload (%llu), new payload is %llu\n",
1455 value,
1456 payload);
1457#endif
1458 return GNUNET_OK;
1459}
1460
1461
1462static void
1463process_stat_done (void *cls,
1464 int success)
1465{
1466 struct DatastorePlugin *plugin = cls;
1467
1468 stat_get = NULL;
1469 if (stats_worked == GNUNET_NO)
1470 payload = plugin->api->get_size (plugin->api->cls);
1471}
1472
1473
1474/**
1354 * Load the datastore plugin. 1475 * Load the datastore plugin.
1355 */ 1476 */
1356static struct DatastorePlugin * 1477static struct DatastorePlugin *
@@ -1373,6 +1494,8 @@ load_plugin ()
1373 ret = GNUNET_malloc (sizeof(struct DatastorePlugin)); 1494 ret = GNUNET_malloc (sizeof(struct DatastorePlugin));
1374 ret->env.cfg = cfg; 1495 ret->env.cfg = cfg;
1375 ret->env.sched = sched; 1496 ret->env.sched = sched;
1497 ret->env.duc = &disk_utilization_change_cb;
1498 ret->env.cls = NULL;
1376 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1499 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1377 _("Loading `%s' datastore plugin\n"), name); 1500 _("Loading `%s' datastore plugin\n"), name);
1378 GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); 1501 GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
@@ -1426,6 +1549,13 @@ unload_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1426 GNUNET_CONTAINER_bloomfilter_free (filter); 1549 GNUNET_CONTAINER_bloomfilter_free (filter);
1427 filter = NULL; 1550 filter = NULL;
1428 } 1551 }
1552 if (lastSync > 0)
1553 sync_stats ();
1554 if (stat_get != NULL)
1555 {
1556 GNUNET_STATISTICS_get_cancel (stat_get);
1557 stat_get = NULL;
1558 }
1429 if (stats != NULL) 1559 if (stats != NULL)
1430 { 1560 {
1431 GNUNET_STATISTICS_destroy (stats, GNUNET_YES); 1561 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
@@ -1614,6 +1744,13 @@ run (void *cls,
1614 } 1744 }
1615 return; 1745 return;
1616 } 1746 }
1747 stat_get = GNUNET_STATISTICS_get (stats,
1748 "datastore",
1749 QUOTA_STAT_NAME,
1750 GNUNET_TIME_UNIT_SECONDS,
1751 &process_stat_done,
1752 &process_stat_in,
1753 plugin);
1617 GNUNET_SERVER_disconnect_notify (server, &cleanup_reservations, NULL); 1754 GNUNET_SERVER_disconnect_notify (server, &cleanup_reservations, NULL);
1618 GNUNET_SERVER_add_handlers (server, handlers); 1755 GNUNET_SERVER_add_handlers (server, handlers);
1619 expired_kill_task 1756 expired_kill_task
diff --git a/src/datastore/perf_plugin_datastore.c b/src/datastore/perf_plugin_datastore.c
index 17cd009bc..4d39d85ac 100644
--- a/src/datastore/perf_plugin_datastore.c
+++ b/src/datastore/perf_plugin_datastore.c
@@ -81,6 +81,20 @@ struct CpsRunContext
81}; 81};
82 82
83 83
84/**
85 * Function called by plugins to notify us about a
86 * change in their disk utilization.
87 *
88 * @param cls closure (NULL)
89 * @param delta change in disk utilization,
90 * 0 for "reset to empty"
91 */
92static void
93disk_utilization_change_cb (void *cls,
94 int delta)
95{
96}
97
84 98
85static void 99static void
86putValue (struct GNUNET_DATASTORE_PluginFunctions * api, int i, int k) 100putValue (struct GNUNET_DATASTORE_PluginFunctions * api, int i, int k)
@@ -331,6 +345,8 @@ load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg,
331 } 345 }
332 env.cfg = cfg; 346 env.cfg = cfg;
333 env.sched = sched; 347 env.sched = sched;
348 env.duc = &disk_utilization_change_cb;
349 env.cls = NULL;
334 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 350 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
335 _("Loading `%s' datastore plugin\n"), name); 351 _("Loading `%s' datastore plugin\n"), name);
336 GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name); 352 GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
diff --git a/src/datastore/plugin_datastore.h b/src/datastore/plugin_datastore.h
index e8f433671..fa08501cc 100644
--- a/src/datastore/plugin_datastore.h
+++ b/src/datastore/plugin_datastore.h
@@ -22,10 +22,6 @@
22 * @file datastore/plugin_datastore.h 22 * @file datastore/plugin_datastore.h
23 * @brief API for the database backend plugins. 23 * @brief API for the database backend plugins.
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - consider defining enumeration or at least typedef
28 * for the type of "type" (instead of using uint32_t)
29 */ 25 */
30#ifndef PLUGIN_DATASTORE_H 26#ifndef PLUGIN_DATASTORE_H
31#define PLUGIN_DATASTORE_H 27#define PLUGIN_DATASTORE_H
@@ -39,12 +35,24 @@
39 35
40/** 36/**
41 * How many bytes of overhead will we assume per entry 37 * How many bytes of overhead will we assume per entry
42 * in the SQlite DB? 38 * in any DB (for reservations)?
43 */ 39 */
44#define GNUNET_DATASTORE_ENTRY_OVERHEAD 256 40#define GNUNET_DATASTORE_ENTRY_OVERHEAD 256
45 41
46 42
47/** 43/**
44 * Function invoked to notify service of disk utilization
45 * changes.
46 *
47 * @param cls closure
48 * @param delta change in disk utilization,
49 * 0 for "reset to empty"
50 */
51typedef void (*DiskUtilizationChange)(void *cls,
52 int delta);
53
54
55/**
48 * The datastore service will pass a pointer to a struct 56 * The datastore service will pass a pointer to a struct
49 * of this type as the first and only argument to the 57 * of this type as the first and only argument to the
50 * entry point of each datastore plugin. 58 * entry point of each datastore plugin.
@@ -61,6 +69,16 @@ struct GNUNET_DATASTORE_PluginEnvironment
61 */ 69 */
62 struct GNUNET_SCHEDULER_Handle *sched; 70 struct GNUNET_SCHEDULER_Handle *sched;
63 71
72 /**
73 * Function to call on disk utilization change.
74 */
75 DiskUtilizationChange duc;
76
77 /**
78 * Closure.
79 */
80 void *cls;
81
64}; 82};
65 83
66 84
diff --git a/src/datastore/plugin_datastore_mysql.c b/src/datastore/plugin_datastore_mysql.c
index c216e989c..ea6cc2322 100644
--- a/src/datastore/plugin_datastore_mysql.c
+++ b/src/datastore/plugin_datastore_mysql.c
@@ -191,7 +191,6 @@
191 " ORDER BY expire DESC,vkey DESC LIMIT 1)"\ 191 " ORDER BY expire DESC,vkey DESC LIMIT 1)"\
192 "ORDER BY expire DESC,vkey DESC LIMIT 1" 192 "ORDER BY expire DESC,vkey DESC LIMIT 1"
193 193
194// #define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn072"
195 194
196 195
197struct GNUNET_MysqlStatementHandle 196struct GNUNET_MysqlStatementHandle
@@ -344,12 +343,10 @@ struct Plugin
344#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE vkey=?" 343#define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE vkey=?"
345 struct GNUNET_MysqlStatementHandle *update_entry; 344 struct GNUNET_MysqlStatementHandle *update_entry;
346 345
347 struct GNUNET_MysqlStatementHandle *iter[4]; 346#define SELECT_SIZE "SELECT SUM(BIT_LENGTH(value) DIV 8) FROM gn072"
347 struct GNUNET_MysqlStatementHandle *get_size;
348 348
349 /** 349 struct GNUNET_MysqlStatementHandle *iter[4];
350 * Size of the mysql database on disk.
351 */
352 unsigned long long content_size;
353 350
354}; 351};
355 352
@@ -957,8 +954,11 @@ do_delete_entry_by_vkey (struct Plugin *plugin,
957 return ret; 954 return ret;
958} 955}
959 956
957
960static int 958static int
961return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values) 959return_ok (void *cls,
960 unsigned int num_values,
961 MYSQL_BIND * values)
962{ 962{
963 return GNUNET_OK; 963 return GNUNET_OK;
964} 964}
@@ -1189,7 +1189,9 @@ mysql_next_request_cont (void *next_cls,
1189 { 1189 {
1190 do_delete_value (plugin, vkey); 1190 do_delete_value (plugin, vkey);
1191 do_delete_entry_by_vkey (plugin, vkey); 1191 do_delete_entry_by_vkey (plugin, vkey);
1192 plugin->content_size -= length; 1192 if (length != 0)
1193 plugin->env->duc (plugin->env->cls,
1194 - length);
1193 } 1195 }
1194 return; 1196 return;
1195 END_SET: 1197 END_SET:
@@ -1279,14 +1281,29 @@ iterateHelper (struct Plugin *plugin,
1279 * Get an estimate of how much space the database is 1281 * Get an estimate of how much space the database is
1280 * currently using. 1282 * currently using.
1281 * 1283 *
1282 * @param cls our "struct Plugin*" 1284 * @param cls our "struct Plugin *"
1283 * @return number of bytes used on disk 1285 * @return number of bytes used on disk
1284 */ 1286 */
1285static unsigned long long 1287static unsigned long long
1286mysql_plugin_get_size (void *cls) 1288mysql_plugin_get_size (void *cls)
1287{ 1289{
1288 struct Plugin *plugin = cls; 1290 struct Plugin *plugin = cls;
1289 return plugin->content_size; 1291 MYSQL_BIND cbind[1];
1292 long long total;
1293
1294 memset (cbind, 0, sizeof (cbind));
1295 total = 0;
1296 cbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
1297 cbind[0].buffer = &total;
1298 cbind[0].is_unsigned = GNUNET_NO;
1299 if (GNUNET_OK !=
1300 prepared_statement_run_select (plugin,
1301 plugin->get_size,
1302 1, cbind,
1303 &return_ok, NULL,
1304 -1))
1305 return 0;
1306 return total;
1290} 1307}
1291 1308
1292 1309
@@ -1373,7 +1390,9 @@ mysql_plugin_put (void *cls,
1373 vkey, 1390 vkey,
1374 (unsigned int) size); 1391 (unsigned int) size);
1375#endif 1392#endif
1376 plugin->content_size += size; 1393 if (size > 0)
1394 plugin->env->duc (plugin->env->cls,
1395 size);
1377 return GNUNET_OK; 1396 return GNUNET_OK;
1378} 1397}
1379 1398
@@ -1804,8 +1823,8 @@ mysql_plugin_drop (void *cls)
1804 "DROP TABLE gn090")) || 1823 "DROP TABLE gn090")) ||
1805 (GNUNET_OK != run_statement (plugin, 1824 (GNUNET_OK != run_statement (plugin,
1806 "DROP TABLE gn072"))) 1825 "DROP TABLE gn072")))
1807 return; /* error */ 1826 return; /* error */
1808 plugin->content_size = 0; 1827 plugin->env->duc (plugin->env->cls, 0);
1809} 1828}
1810 1829
1811 1830
@@ -1865,6 +1884,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
1865 || PINIT (plugin->select_entry_by_hash_vhash_and_type, 1884 || PINIT (plugin->select_entry_by_hash_vhash_and_type,
1866 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) 1885 SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE)
1867 || PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH) 1886 || PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH)
1887 || PINIT (plugin->get_size, SELECT_SIZE)
1868 || PINIT (plugin->count_entry_by_hash_and_vhash, COUNT_ENTRY_BY_HASH_AND_VHASH) 1888 || PINIT (plugin->count_entry_by_hash_and_vhash, COUNT_ENTRY_BY_HASH_AND_VHASH)
1869 || PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE) 1889 || PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE)
1870 || PINIT (plugin->count_entry_by_hash_vhash_and_type, 1890 || PINIT (plugin->count_entry_by_hash_vhash_and_type,
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c
index 889309784..54bdde542 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -82,26 +82,104 @@
82#define BUSY_TIMEOUT GNUNET_TIME_UNIT_SECONDS 82#define BUSY_TIMEOUT GNUNET_TIME_UNIT_SECONDS
83 83
84 84
85/**
86 * Closure for 'postgres_next_request_cont'.
87 */
85struct NextRequestClosure 88struct NextRequestClosure
86{ 89{
90 /**
91 * Global plugin data.
92 */
87 struct Plugin *plugin; 93 struct Plugin *plugin;
94
95 /**
96 * Function to call for each matching entry.
97 */
88 PluginIterator iter; 98 PluginIterator iter;
99
100 /**
101 * Closure for 'iter'.
102 */
89 void *iter_cls; 103 void *iter_cls;
104
105 /**
106 * Parameters for the prepared statement.
107 */
90 const char *paramValues[5]; 108 const char *paramValues[5];
109
110 /**
111 * Name of the prepared statement to run.
112 */
91 const char *pname; 113 const char *pname;
114
115 /**
116 * Size of values pointed to by paramValues.
117 */
92 int paramLengths[5]; 118 int paramLengths[5];
119
120 /**
121 * Number of paramters in paramValues/paramLengths.
122 */
93 int nparams; 123 int nparams;
124
125 /**
126 * Current time (possible parameter), big-endian.
127 */
94 uint64_t bnow; 128 uint64_t bnow;
129
130 /**
131 * Key (possible parameter)
132 */
95 GNUNET_HashCode key; 133 GNUNET_HashCode key;
134
135 /**
136 * Hash of value (possible parameter)
137 */
96 GNUNET_HashCode vhash; 138 GNUNET_HashCode vhash;
139
140 /**
141 * Number of entries found so far
142 */
97 long long count; 143 long long count;
144
145 /**
146 * Offset this iteration starts at.
147 */
98 uint64_t off; 148 uint64_t off;
149
150 /**
151 * Current offset to use in query, big-endian.
152 */
99 uint64_t blimit_off; 153 uint64_t blimit_off;
154
155 /**
156 * Overall number of matching entries.
157 */
100 unsigned long long total; 158 unsigned long long total;
159
160 /**
161 * Expiration value of previous result (possible parameter), big-endian.
162 */
101 uint64_t blast_expire; 163 uint64_t blast_expire;
164
165 /**
166 * Row ID of last result (possible paramter), big-endian.
167 */
102 uint32_t blast_rowid; 168 uint32_t blast_rowid;
169
170 /**
171 * Priority of last result (possible parameter), big-endian.
172 */
103 uint32_t blast_prio; 173 uint32_t blast_prio;
174
175 /**
176 * Type of block (possible paramter), big-endian.
177 */
104 uint32_t btype; 178 uint32_t btype;
179
180 /**
181 * Flag set to GNUNET_YES to stop iteration.
182 */
105 int end_it; 183 int end_it;
106}; 184};
107 185
@@ -131,10 +209,6 @@ struct Plugin
131 */ 209 */
132 GNUNET_SCHEDULER_TaskIdentifier next_task; 210 GNUNET_SCHEDULER_TaskIdentifier next_task;
133 211
134 unsigned long long payload;
135
136 unsigned int lastSync;
137
138}; 212};
139 213
140 214
@@ -143,6 +217,12 @@ struct Plugin
143 * the desired status code. If not, log an error, clear the 217 * the desired status code. If not, log an error, clear the
144 * result and return GNUNET_SYSERR. 218 * result and return GNUNET_SYSERR.
145 * 219 *
220 * @param plugin global context
221 * @param ret result to check
222 * @param expected_status expected return value
223 * @param command name of SQL command that was run
224 * @param args arguments to SQL command
225 * @param line line number for error reporting
146 * @return GNUNET_OK if the result is acceptable 226 * @return GNUNET_OK if the result is acceptable
147 */ 227 */
148static int 228static int
@@ -173,6 +253,10 @@ check_result (struct Plugin *plugin,
173 253
174/** 254/**
175 * Run simple SQL statement (without results). 255 * Run simple SQL statement (without results).
256 *
257 * @param plugin global context
258 * @param sql statement to run
259 * @param line code line for error reporting
176 */ 260 */
177static int 261static int
178pq_exec (struct Plugin *plugin, 262pq_exec (struct Plugin *plugin,
@@ -190,6 +274,12 @@ pq_exec (struct Plugin *plugin,
190 274
191/** 275/**
192 * Prepare SQL statement. 276 * Prepare SQL statement.
277 *
278 * @param plugin global context
279 * @param sql SQL code to prepare
280 * @param nparams number of parameters in sql
281 * @param line code line for error reporting
282 * @return GNUNET_OK on success
193 */ 283 */
194static int 284static int
195pq_prepare (struct Plugin *plugin, 285pq_prepare (struct Plugin *plugin,
@@ -207,6 +297,8 @@ pq_prepare (struct Plugin *plugin,
207 297
208/** 298/**
209 * @brief Get a database handle 299 * @brief Get a database handle
300 *
301 * @param plugin global context
210 * @return GNUNET_OK on success, GNUNET_SYSERR on error 302 * @return GNUNET_OK on success, GNUNET_SYSERR on error
211 */ 303 */
212static int 304static int
@@ -413,6 +505,8 @@ init_connection (struct Plugin *plugin)
413 * Delete the row identified by the given rowid (qid 505 * Delete the row identified by the given rowid (qid
414 * in postgres). 506 * in postgres).
415 * 507 *
508 * @param plugin global context
509 * @param rowid which row to delete
416 * @return GNUNET_OK on success 510 * @return GNUNET_OK on success
417 */ 511 */
418static int 512static int
@@ -450,11 +544,32 @@ static unsigned long long
450postgres_plugin_get_size (void *cls) 544postgres_plugin_get_size (void *cls)
451{ 545{
452 struct Plugin *plugin = cls; 546 struct Plugin *plugin = cls;
453 double ret; 547 unsigned long long total;
548 PGresult *ret;
454 549
455 ret = plugin->payload; 550 ret = PQexecParams (plugin->dbh,
456 return (unsigned long long) (ret * 1.00); 551 "SELECT SUM(LENGTH(value))+256*COUNT(*) FROM gn090",
457 /* benchmarking shows XX% overhead */ 552 0, NULL, NULL, NULL, NULL, 1);
553 if (GNUNET_OK != check_result (plugin,
554 ret,
555 PGRES_TUPLES_OK,
556 "PQexecParams",
557 "get_size",
558 __LINE__))
559 {
560 return 0;
561 }
562 if ((PQntuples (ret) != 1) ||
563 (PQnfields (ret) != 1) ||
564 (PQgetlength (ret, 0, 0) != sizeof (unsigned long long)))
565 {
566 GNUNET_break (0);
567 PQclear (ret);
568 return 0;
569 }
570 total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0));
571 PQclear (ret);
572 return total;
458} 573}
459 574
460 575
@@ -518,13 +633,12 @@ postgres_plugin_put (void *cls,
518 "PQexecPrepared", "put", __LINE__)) 633 "PQexecPrepared", "put", __LINE__))
519 return GNUNET_SYSERR; 634 return GNUNET_SYSERR;
520 PQclear (ret); 635 PQclear (ret);
521 plugin->payload += size; 636 plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
522#if DEBUG_POSTGRES 637#if DEBUG_POSTGRES
523 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 638 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
524 "datastore-postgres", 639 "datastore-postgres",
525 "Stored %u bytes in database, new payload is %llu\n", 640 "Stored %u bytes in database\n",
526 (unsigned int) size, 641 (unsigned int) size);
527 (unsigned long long) plugin->payload);
528#endif 642#endif
529 return GNUNET_OK; 643 return GNUNET_OK;
530} 644}
@@ -695,18 +809,16 @@ postgres_next_request_cont (void *next_cls,
695#if DEBUG_POSTGRES 809#if DEBUG_POSTGRES
696 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 810 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
697 "datastore-postgres", 811 "datastore-postgres",
698 "Deleting %u bytes from database, current payload is %llu\n", 812 "Deleting %u bytes from database\n",
699 (unsigned int) size, 813 (unsigned int) size);
700 (unsigned long long) plugin->payload);
701#endif 814#endif
702 GNUNET_assert (plugin->payload >= size); 815 plugin->env->duc (plugin->env->cls,
703 plugin->payload -= size; 816 - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
704#if DEBUG_POSTGRES 817#if DEBUG_POSTGRES
705 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 818 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
706 "datastore-postgres", 819 "datastore-postgres",
707 "Deleted %u bytes from database, new payload is %llu\n", 820 "Deleted %u bytes from database\n",
708 (unsigned int) size, 821 (unsigned int) size);
709 (unsigned long long) plugin->payload);
710#endif 822#endif
711 } 823 }
712 } 824 }
@@ -803,11 +915,15 @@ postgres_plugin_update (void *cls,
803 * Call a method for each key in the database and 915 * Call a method for each key in the database and
804 * call the callback method on it. 916 * call the callback method on it.
805 * 917 *
918 * @param plugin global context
806 * @param type entries of which type should be considered? 919 * @param type entries of which type should be considered?
920 * @param is_asc ascending or descending iteration?
921 * @param iter_select which SELECT method should be used?
807 * @param iter maybe NULL (to just count); iter 922 * @param iter maybe NULL (to just count); iter
808 * should return GNUNET_SYSERR to abort the 923 * should return GNUNET_SYSERR to abort the
809 * iteration, GNUNET_NO to delete the entry and 924 * iteration, GNUNET_NO to delete the entry and
810 * continue and GNUNET_OK to continue iterating 925 * continue and GNUNET_OK to continue iterating
926 * @param iter_cls closure for 'iter'
811 */ 927 */
812static void 928static void
813postgres_iterate (struct Plugin *plugin, 929postgres_iterate (struct Plugin *plugin,
@@ -1123,7 +1239,6 @@ postgres_plugin_iter_ascending_expiration (void *cls,
1123} 1239}
1124 1240
1125 1241
1126
1127/** 1242/**
1128 * Select a subset of the items in the datastore and call 1243 * Select a subset of the items in the datastore and call
1129 * the given iterator for each of them. 1244 * the given iterator for each of them.
@@ -1148,7 +1263,6 @@ postgres_plugin_iter_migration_order (void *cls,
1148} 1263}
1149 1264
1150 1265
1151
1152/** 1266/**
1153 * Select a subset of the items in the datastore and call 1267 * Select a subset of the items in the datastore and call
1154 * the given iterator for each of them. 1268 * the given iterator for each of them.
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index ca1f4e4ae..076d468ee 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -25,19 +25,11 @@
25 */ 25 */
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_statistics_service.h"
29#include "plugin_datastore.h" 28#include "plugin_datastore.h"
30#include <sqlite3.h> 29#include <sqlite3.h>
31 30
32#define DEBUG_SQLITE GNUNET_NO 31#define DEBUG_SQLITE GNUNET_NO
33 32
34/**
35 * After how many payload-changing operations
36 * do we sync our statistics?
37 */
38#define MAX_STAT_SYNC_LAG 50
39
40#define QUOTA_STAT_NAME gettext_noop ("# bytes used in file-sharing datastore")
41 33
42/** 34/**
43 * Log an error message at log-level 'level' that indicates 35 * Log an error message at log-level 'level' that indicates
@@ -123,16 +115,6 @@ struct Plugin
123 sqlite3_stmt *insertContent; 115 sqlite3_stmt *insertContent;
124 116
125 /** 117 /**
126 * Handle to the statistics service.
127 */
128 struct GNUNET_STATISTICS_Handle *statistics;
129
130 /**
131 * Handle for pending get request.
132 */
133 struct GNUNET_STATISTICS_GetHandle *stat_get;
134
135 /**
136 * Closure of the 'next_task' (must be freed if 'next_task' is cancelled). 118 * Closure of the 'next_task' (must be freed if 'next_task' is cancelled).
137 */ 119 */
138 struct NextContext *next_task_nc; 120 struct NextContext *next_task_nc;
@@ -141,29 +123,12 @@ struct Plugin
141 * Pending task with scheduler for running the next request. 123 * Pending task with scheduler for running the next request.
142 */ 124 */
143 GNUNET_SCHEDULER_TaskIdentifier next_task; 125 GNUNET_SCHEDULER_TaskIdentifier next_task;
144
145 /**
146 * How much data are we currently storing
147 * in the database?
148 */
149 unsigned long long payload;
150
151 /**
152 * Number of updates that were made to the
153 * payload value since we last synchronized
154 * it with the statistics service.
155 */
156 unsigned int lastSync;
157 126
158 /** 127 /**
159 * Should the database be dropped on shutdown? 128 * Should the database be dropped on shutdown?
160 */ 129 */
161 int drop_on_shutdown; 130 int drop_on_shutdown;
162 131
163 /**
164 * Did we get an answer from statistics?
165 */
166 int stats_worked;
167}; 132};
168 133
169 134
@@ -267,12 +232,7 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
267 return GNUNET_SYSERR; 232 return GNUNET_SYSERR;
268 } 233 }
269 /* database is new or got deleted, reset payload to zero! */ 234 /* database is new or got deleted, reset payload to zero! */
270 if (plugin->stat_get != NULL) 235 plugin->env->duc (plugin->env->cls, 0);
271 {
272 GNUNET_STATISTICS_get_cancel (plugin->stat_get);
273 plugin->stat_get = NULL;
274 }
275 plugin->payload = 0;
276 } 236 }
277 plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir), 237 plugin->fn = GNUNET_STRINGS_to_utf8 (afsdir, strlen (afsdir),
278#ifdef ENABLE_NLS 238#ifdef ENABLE_NLS
@@ -375,22 +335,6 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
375 335
376 336
377/** 337/**
378 * Synchronize our utilization statistics with the
379 * statistics service.
380 * @param plugin the plugin context (state for this module)
381 */
382static void
383sync_stats (struct Plugin *plugin)
384{
385 GNUNET_STATISTICS_set (plugin->statistics,
386 QUOTA_STAT_NAME,
387 plugin->payload,
388 GNUNET_YES);
389 plugin->lastSync = 0;
390}
391
392
393/**
394 * Shutdown database connection and associate data 338 * Shutdown database connection and associate data
395 * structures. 339 * structures.
396 * @param plugin the plugin context (state for this module) 340 * @param plugin the plugin context (state for this module)
@@ -398,8 +342,6 @@ sync_stats (struct Plugin *plugin)
398static void 342static void
399database_shutdown (struct Plugin *plugin) 343database_shutdown (struct Plugin *plugin)
400{ 344{
401 if (plugin->lastSync > 0)
402 sync_stats (plugin);
403 if (plugin->updPrio != NULL) 345 if (plugin->updPrio != NULL)
404 sqlite3_finalize (plugin->updPrio); 346 sqlite3_finalize (plugin->updPrio);
405 if (plugin->insertContent != NULL) 347 if (plugin->insertContent != NULL)
@@ -410,20 +352,6 @@ database_shutdown (struct Plugin *plugin)
410 352
411 353
412/** 354/**
413 * Get an estimate of how much space the database is
414 * currently using.
415 *
416 * @param cls our plugin context
417 * @return number of bytes used on disk
418 */
419static unsigned long long sqlite_plugin_get_size (void *cls)
420{
421 struct Plugin *plugin = cls;
422 return plugin->payload;
423}
424
425
426/**
427 * Delete the database entry with the given 355 * Delete the database entry with the given
428 * row identifier. 356 * row identifier.
429 * 357 *
@@ -661,23 +589,15 @@ sqlite_next_request_cont (void *cls,
661 if ( (ret == GNUNET_NO) && 589 if ( (ret == GNUNET_NO) &&
662 (GNUNET_OK == delete_by_rowid (plugin, rowid)) ) 590 (GNUNET_OK == delete_by_rowid (plugin, rowid)) )
663 { 591 {
664 if (plugin->payload >= size + GNUNET_DATASTORE_ENTRY_OVERHEAD) 592 plugin->env->duc (plugin->env->cls,
665 plugin->payload -= (size + GNUNET_DATASTORE_ENTRY_OVERHEAD); 593 - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
666 else
667 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
668 _("Datastore payload inaccurate, please fix and restart!\n"));
669 plugin->lastSync++;
670#if DEBUG_SQLITE 594#if DEBUG_SQLITE
671 if (ret == GNUNET_NO) 595 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
672 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 596 "sqlite",
673 "sqlite", 597 "Removed entry %llu (%u bytes)\n",
674 "Removed entry %llu (%u bytes), new payload is %llu\n", 598 (unsigned long long) rowid,
675 (unsigned long long) rowid, 599 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
676 size + GNUNET_DATASTORE_ENTRY_OVERHEAD,
677 plugin->payload);
678#endif 600#endif
679 if (plugin->lastSync >= MAX_STAT_SYNC_LAG)
680 sync_stats (plugin);
681 } 601 }
682} 602}
683 603
@@ -798,17 +718,14 @@ sqlite_plugin_put (void *cls,
798 LOG_SQLITE (plugin, NULL, 718 LOG_SQLITE (plugin, NULL,
799 GNUNET_ERROR_TYPE_ERROR | 719 GNUNET_ERROR_TYPE_ERROR |
800 GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); 720 GNUNET_ERROR_TYPE_BULK, "sqlite3_reset");
801 plugin->lastSync++; 721 plugin->env->duc (plugin->env->cls,
802 plugin->payload += size + GNUNET_DATASTORE_ENTRY_OVERHEAD; 722 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
803#if DEBUG_SQLITE 723#if DEBUG_SQLITE
804 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 724 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
805 "sqlite", 725 "sqlite",
806 "Stored new entry (%u bytes), new payload is %llu\n", 726 "Stored new entry (%u bytes)\n",
807 size + GNUNET_DATASTORE_ENTRY_OVERHEAD, 727 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
808 plugin->payload);
809#endif 728#endif
810 if (plugin->lastSync >= MAX_STAT_SYNC_LAG)
811 sync_stats (plugin);
812 return GNUNET_OK; 729 return GNUNET_OK;
813} 730}
814 731
@@ -1574,81 +1491,50 @@ sqlite_plugin_drop (void *cls)
1574} 1491}
1575 1492
1576 1493
1577/** 1494static unsigned long long
1578 * Callback function to process statistic values. 1495sqlite_plugin_get_size (void *cls)
1579 *
1580 * @param cls closure
1581 * @param subsystem name of subsystem that created the statistic
1582 * @param name the name of the datum
1583 * @param value the current value
1584 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
1585 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
1586 */
1587static int
1588process_stat_in (void *cls,
1589 const char *subsystem,
1590 const char *name,
1591 uint64_t value,
1592 int is_persistent)
1593{
1594 struct Plugin *plugin = cls;
1595
1596 plugin->stats_worked = GNUNET_YES;
1597 plugin->payload += value;
1598#if DEBUG_SQLITE
1599 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1600 "sqlite",
1601 "Notification from statistics about existing payload (%llu), new payload is %llu\n",
1602 value,
1603 plugin->payload);
1604#endif
1605 return GNUNET_OK;
1606}
1607
1608
1609static void
1610process_stat_done (void *cls,
1611 int success)
1612{ 1496{
1613 struct Plugin *plugin = cls; 1497 struct Plugin *plugin = cls;
1614 sqlite3_stmt *stmt; 1498 sqlite3_stmt *stmt;
1615 uint64_t pages; 1499 uint64_t pages;
1616 uint64_t page_size; 1500 uint64_t page_size;
1617 1501
1618 plugin->stat_get = NULL; 1502 if (SQLITE_VERSION_NUMBER < 3006000)
1619 if ( (plugin->stats_worked == GNUNET_NO) && 1503 {
1620 (SQLITE_VERSION_NUMBER >= 3006000) ) 1504 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1621 { 1505 "datastore-sqlite",
1622 CHECK (SQLITE_OK == 1506 _("sqlite version to old to determine size, assuming zero\n"));
1623 sqlite3_exec (plugin->dbh, 1507 return 0;
1624 "VACUUM", NULL, NULL, ENULL));
1625 CHECK (SQLITE_OK ==
1626 sqlite3_exec (plugin->dbh,
1627 "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL));
1628 CHECK (SQLITE_OK ==
1629 sq_prepare (plugin->dbh,
1630 "PRAGMA page_count",
1631 &stmt));
1632 if (SQLITE_ROW ==
1633 sqlite3_step (stmt))
1634 pages = sqlite3_column_int64 (stmt, 0);
1635 else
1636 pages = 0;
1637 sqlite3_finalize (stmt);
1638 CHECK (SQLITE_OK ==
1639 sq_prepare (plugin->dbh,
1640 "PRAGMA page_size",
1641 &stmt));
1642 CHECK (SQLITE_ROW ==
1643 sqlite3_step (stmt));
1644 page_size = sqlite3_column_int64 (stmt, 0);
1645 sqlite3_finalize (stmt);
1646 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1647 _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1648 (unsigned long long) pages,
1649 (unsigned long long) page_size);
1650 plugin->payload = pages * page_size;
1651 } 1508 }
1509 CHECK (SQLITE_OK ==
1510 sqlite3_exec (plugin->dbh,
1511 "VACUUM", NULL, NULL, ENULL));
1512 CHECK (SQLITE_OK ==
1513 sqlite3_exec (plugin->dbh,
1514 "PRAGMA auto_vacuum=INCREMENTAL", NULL, NULL, ENULL));
1515 CHECK (SQLITE_OK ==
1516 sq_prepare (plugin->dbh,
1517 "PRAGMA page_count",
1518 &stmt));
1519 if (SQLITE_ROW ==
1520 sqlite3_step (stmt))
1521 pages = sqlite3_column_int64 (stmt, 0);
1522 else
1523 pages = 0;
1524 sqlite3_finalize (stmt);
1525 CHECK (SQLITE_OK ==
1526 sq_prepare (plugin->dbh,
1527 "PRAGMA page_size",
1528 &stmt));
1529 CHECK (SQLITE_ROW ==
1530 sqlite3_step (stmt));
1531 page_size = sqlite3_column_int64 (stmt, 0);
1532 sqlite3_finalize (stmt);
1533 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1534 _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
1535 (unsigned long long) pages,
1536 (unsigned long long) page_size);
1537 return pages * page_size;
1652} 1538}
1653 1539
1654 1540
@@ -1669,16 +1555,6 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
1669 return NULL; /* can only initialize once! */ 1555 return NULL; /* can only initialize once! */
1670 memset (&plugin, 0, sizeof(struct Plugin)); 1556 memset (&plugin, 0, sizeof(struct Plugin));
1671 plugin.env = env; 1557 plugin.env = env;
1672 plugin.statistics = GNUNET_STATISTICS_create (env->sched,
1673 "ds-sqlite",
1674 env->cfg);
1675 plugin.stat_get = GNUNET_STATISTICS_get (plugin.statistics,
1676 "ds-sqlite",
1677 QUOTA_STAT_NAME,
1678 GNUNET_TIME_UNIT_SECONDS,
1679 &process_stat_done,
1680 &process_stat_in,
1681 &plugin);
1682 if (GNUNET_OK != 1558 if (GNUNET_OK !=
1683 database_setup (env->cfg, &plugin)) 1559 database_setup (env->cfg, &plugin))
1684 { 1560 {
@@ -1717,11 +1593,6 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
1717 struct GNUNET_DATASTORE_PluginFunctions *api = cls; 1593 struct GNUNET_DATASTORE_PluginFunctions *api = cls;
1718 struct Plugin *plugin = api->cls; 1594 struct Plugin *plugin = api->cls;
1719 1595
1720 if (plugin->stat_get != NULL)
1721 {
1722 GNUNET_STATISTICS_get_cancel (plugin->stat_get);
1723 plugin->stat_get = NULL;
1724 }
1725 if (plugin->next_task != GNUNET_SCHEDULER_NO_TASK) 1596 if (plugin->next_task != GNUNET_SCHEDULER_NO_TASK)
1726 { 1597 {
1727 GNUNET_SCHEDULER_cancel (plugin->env->sched, 1598 GNUNET_SCHEDULER_cancel (plugin->env->sched,
@@ -1735,10 +1606,7 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
1735 if (plugin->drop_on_shutdown) 1606 if (plugin->drop_on_shutdown)
1736 fn = GNUNET_strdup (plugin->fn); 1607 fn = GNUNET_strdup (plugin->fn);
1737 database_shutdown (plugin); 1608 database_shutdown (plugin);
1738 GNUNET_STATISTICS_destroy (plugin->statistics,
1739 GNUNET_NO);
1740 plugin->env = NULL; 1609 plugin->env = NULL;
1741 plugin->payload = 0;
1742 GNUNET_free (api); 1610 GNUNET_free (api);
1743 if (fn != NULL) 1611 if (fn != NULL)
1744 { 1612 {