sqlite clean up
[oweals/gnunet.git] / src / datastore / perf_plugin_datastore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2004, 2005, 2006, 2007, 2009 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  * @file perf_plugin_datastore.c
22  * @brief Profile database plugin directly, focusing on iterators.
23  * @author Christian Grothoff
24  */
25
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_datastore_plugin.h"
30
31 #define VERBOSE GNUNET_NO
32
33 /**
34  * Target datastore size (in bytes).  Realistic sizes are
35  * more like 16 GB (not the default of 16 MB); however,
36  * those take too long to run them in the usual "make check"
37  * sequence.  Hence the value used for shipping is tiny.
38  */
39 #define MAX_SIZE 1024LL * 1024 * 128
40
41 #define ITERATIONS 10
42
43 /**
44  * Number of put operations equivalent to 1/10th of MAX_SIZE
45  */
46 #define PUT_10 (MAX_SIZE / 32 / 1024 / ITERATIONS)
47
48 static unsigned long long stored_bytes;
49
50 static unsigned long long stored_entries;
51
52 static unsigned long long stored_ops;
53
54 static const char *plugin_name;
55
56 static int ok;
57
58 enum RunPhase
59   {
60     RP_DONE = 0,
61     RP_PUT,
62     RP_LP_GET,
63     RP_AE_GET,
64     RP_ZA_GET,
65     RP_AN_GET
66   };
67
68
69 struct CpsRunContext
70 {
71   unsigned int i;
72   struct GNUNET_TIME_Absolute start;
73   struct GNUNET_TIME_Absolute end;
74   const struct GNUNET_CONFIGURATION_Handle *cfg;
75   struct GNUNET_DATASTORE_PluginFunctions * api;
76   const char *msg;
77   enum RunPhase phase;
78   unsigned int cnt;
79 };
80
81
82 /**
83  * Function called by plugins to notify us about a
84  * change in their disk utilization.
85  *
86  * @param cls closure (NULL)
87  * @param delta change in disk utilization, 
88  *        0 for "reset to empty"
89  */
90 static void
91 disk_utilization_change_cb (void *cls,
92                             int delta)
93 {
94 }
95
96              
97 static void
98 putValue (struct GNUNET_DATASTORE_PluginFunctions * api, int i, int k)
99 {
100   char value[65536];
101   size_t size;
102   static GNUNET_HashCode key;
103   static int ic;
104   char *msg;
105   unsigned int prio;
106
107   /* most content is 32k */
108   size = 32 * 1024;
109
110   if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16) == 0)  /* but some of it is less! */
111     size = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 32 * 1024);
112   size = size - (size & 7);     /* always multiple of 8 */
113
114   /* generate random key */
115   key.bits[0] = (unsigned int) GNUNET_TIME_absolute_get ().abs_value;
116   GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &key);
117   memset (value, i, size);
118   if (i > 255)
119     memset (value, i - 255, size / 2);
120   value[0] = k;
121   msg = NULL;
122   prio = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
123   if (GNUNET_OK != api->put (api->cls,
124                              &key, 
125                              size,
126                              value,
127                              i /* type */,
128                              prio,
129                              i /* anonymity */,
130                              0 /* replication */,
131                              GNUNET_TIME_relative_to_absolute 
132                              (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
133                                                              60 * 60 * 60 * 1000 +
134                                                              GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000))),
135                              &msg))
136     {
137       fprintf (stderr, "ERROR: `%s'\n", msg);
138       GNUNET_free_non_null (msg);
139       return;
140     }
141   ic++;
142   stored_bytes += size;
143   stored_ops++;
144   stored_entries++;
145 }
146
147 static void
148 test (void *cls,
149       const struct GNUNET_SCHEDULER_TaskContext *tc);
150
151
152 static int
153 iterateDummy (void *cls,
154               void *next_cls,
155               const GNUNET_HashCode * key,
156               uint32_t size,
157               const void *data,
158               enum GNUNET_BLOCK_Type type,
159               uint32_t priority,
160               uint32_t anonymity,
161               struct GNUNET_TIME_Absolute
162               expiration, 
163               uint64_t uid)
164 {
165   struct CpsRunContext *crc = cls;
166   
167   if (key == NULL)
168     {
169       crc->end = GNUNET_TIME_absolute_get();
170       printf (crc->msg,
171               crc->i,
172               (unsigned long long) (crc->end.abs_value - crc->start.abs_value),
173               crc->cnt);
174       if (crc->phase != RP_AN_GET)
175         {
176           crc->phase++;
177         }
178       else
179         {
180           if (crc->i == ITERATIONS)
181             crc->phase = RP_DONE;
182           else
183             crc->phase = RP_PUT;
184         }
185       crc->cnt = 0;
186       crc->start = GNUNET_TIME_absolute_get ();      
187       GNUNET_SCHEDULER_add_now (&test, crc);
188       return GNUNET_OK;
189     }
190 #if VERBOSE
191   fprintf (stderr, "Found result type=%u, priority=%u, size=%u, expire=%llu\n",
192            type, priority, size,
193            (unsigned long long) expiration.abs_value);
194 #endif
195   crc->cnt++;
196   crc->api->next_request (next_cls,
197                           GNUNET_NO);
198   return GNUNET_OK;
199 }
200
201
202
203 static int
204 dummy_get (void *cls,
205            void *next_cls,
206            const GNUNET_HashCode * key,
207            uint32_t size,
208            const void *data,
209            enum GNUNET_BLOCK_Type type,
210            uint32_t priority,
211            uint32_t anonymity,
212            struct GNUNET_TIME_Absolute
213            expiration, 
214            uint64_t uid)
215 {
216   struct CpsRunContext *crc = cls;
217
218   crc->cnt++;
219   if (1000 == crc->cnt)
220     {
221       crc->end = GNUNET_TIME_absolute_get();
222       printf (crc->msg,
223               crc->i,
224               (unsigned long long) (crc->end.abs_value - crc->start.abs_value),
225               crc->cnt);
226       crc->phase++;
227       crc->cnt = 0;
228       crc->start = GNUNET_TIME_absolute_get ();      
229     }
230   GNUNET_SCHEDULER_add_now (&test, crc);
231   return GNUNET_OK;
232 }
233
234 /**
235  * Function called when the service shuts
236  * down.  Unloads our datastore plugin.
237  *
238  * @param api api to unload
239  * @param cfg configuration to use
240  */
241 static void
242 unload_plugin (struct GNUNET_DATASTORE_PluginFunctions * api,
243                const struct GNUNET_CONFIGURATION_Handle *cfg)
244 {
245   char *name;
246   char *libname;
247
248   if (GNUNET_OK !=
249       GNUNET_CONFIGURATION_get_value_string (cfg,
250                                              "DATASTORE", "DATABASE", &name))
251     {
252       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
253                   _("No `%s' specified for `%s' in configuration!\n"),
254                   "DATABASE",
255                   "DATASTORE");
256       return;
257     }
258   GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
259   GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
260   GNUNET_free (libname);
261   GNUNET_free (name);
262 }
263
264
265
266 /**
267  * Last task run during shutdown.  Disconnects us from
268  * the transport and core.
269  */
270 static void
271 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
272 {
273   struct CpsRunContext *crc = cls;
274
275   unload_plugin (crc->api, crc->cfg);
276   GNUNET_free (crc);
277 }
278
279
280 static void
281 test (void *cls,
282       const struct GNUNET_SCHEDULER_TaskContext *tc)
283 {  
284   struct CpsRunContext *crc = cls;
285   int j;
286
287   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
288     {
289       crc->phase = RP_DONE;
290       ok = 1;
291     }
292   switch (crc->phase)
293     {
294     case RP_PUT:      
295       crc->start = GNUNET_TIME_absolute_get ();
296       for (j=0;j<PUT_10;j++)
297         putValue (crc->api, j, crc->i);
298       crc->end = GNUNET_TIME_absolute_get ();
299       printf ("%3u insertion took                      %20llums for %u\n",
300               crc->i,
301               (unsigned long long) (crc->end.abs_value - crc->start.abs_value),
302               (unsigned int) PUT_10);
303       crc->i++;
304       crc->start = GNUNET_TIME_absolute_get ();      
305       crc->phase = RP_LP_GET;
306       GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK,
307                                   &test, crc);
308       break;
309     case RP_LP_GET:
310       crc->msg = "%3u replication iteration took %20llums for %u\n";
311       crc->api->replication_get (crc->api->cls, 
312                                  &dummy_get,
313                                  crc);
314       break;
315     case RP_AE_GET:
316       crc->msg = "%3u expiration iteration took %20llums for %u\n";
317       crc->api->expiration_get (crc->api->cls, 
318                                 &dummy_get,
319                                 crc);
320       break;
321     case RP_ZA_GET:
322       crc->msg = "%3u zero anonymity iteration took %20llums for %u\n";
323       crc->api->iter_zero_anonymity (crc->api->cls, 0, 
324                                      &iterateDummy,
325                                      crc);
326       break;
327     case RP_AN_GET:
328       crc->msg = "%3u all now iteration took %20llums for %u\n";
329       crc->api->iter_all_now (crc->api->cls, 0,
330                               &iterateDummy,
331                               crc);
332       break;
333     case RP_DONE:
334       crc->api->drop (crc->api->cls);
335       GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE,
336                                           &cleaning_task, crc);
337       break;
338     }
339 }
340
341
342 /**
343  * Load the datastore plugin.
344  */
345 static struct GNUNET_DATASTORE_PluginFunctions *
346 load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
347 {
348   static struct GNUNET_DATASTORE_PluginEnvironment env;
349   struct GNUNET_DATASTORE_PluginFunctions * ret; 
350   char *name;
351   char *libname;
352
353   if (GNUNET_OK !=
354       GNUNET_CONFIGURATION_get_value_string (cfg,
355                                              "DATASTORE", "DATABASE", &name))
356     {
357       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
358                   _("No `%s' specified for `%s' in configuration!\n"),
359                   "DATABASE",
360                   "DATASTORE");
361       return NULL;
362     }
363   env.cfg = cfg;
364   env.duc = &disk_utilization_change_cb;
365   env.cls = NULL;
366   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
367               _("Loading `%s' datastore plugin\n"), name);
368   GNUNET_asprintf (&libname, "libgnunet_plugin_datastore_%s", name);
369   if (NULL == (ret = GNUNET_PLUGIN_load (libname, &env)))
370     {
371       fprintf (stderr,
372                "Failed to load plugin `%s'!\n",
373                name);
374       return NULL;
375     }
376   GNUNET_free (libname);
377   GNUNET_free (name);
378   return ret;
379 }
380
381
382 static void
383 run (void *cls,
384      char *const *args,
385      const char *cfgfile,
386      const struct GNUNET_CONFIGURATION_Handle *c)
387 {
388   struct GNUNET_DATASTORE_PluginFunctions *api;
389   struct CpsRunContext *crc;
390
391   api = load_plugin (c);
392   if (api == NULL)
393     {
394       fprintf (stderr, 
395                "Could not initialize plugin, assuming database not configured. Test not run!\n");
396       return;
397     }
398   crc = GNUNET_malloc(sizeof(struct CpsRunContext));
399   crc->api = api;
400   crc->cfg = c;
401   crc->phase = RP_PUT;
402   GNUNET_SCHEDULER_add_now (&test, crc);
403 }
404
405
406 static int
407 check ()
408 {
409   char cfg_name[128];
410   char *const argv[] = { 
411     "perf-plugin-datastore",
412     "-c",
413     cfg_name,
414 #if VERBOSE
415     "-L", "DEBUG",
416 #endif
417     NULL
418   };
419   struct GNUNET_GETOPT_CommandLineOption options[] = {
420     GNUNET_GETOPT_OPTION_END
421   };
422
423   GNUNET_snprintf (cfg_name,
424                    sizeof (cfg_name),
425                    "perf_plugin_datastore_data_%s.conf",
426                    plugin_name);
427   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
428                       argv, "perf-plugin-datastore", "nohelp",
429                       options, &run, NULL);
430   if (ok != 0)
431     fprintf (stderr, "Missed some testcases: %u\n", ok);
432   return ok;
433 }
434
435
436 int
437 main (int argc, char *argv[])
438 {
439   int ret;
440   char *pos;
441   char dir_name[128];
442
443   /* determine name of plugin to use */
444   plugin_name = argv[0];
445   while (NULL != (pos = strstr(plugin_name, "_")))
446     plugin_name = pos+1;
447   if (NULL != (pos = strstr(plugin_name, ".")))
448     pos[0] = 0;
449   else
450     pos = (char *) plugin_name;
451
452   GNUNET_snprintf (dir_name,
453                    sizeof (dir_name),
454                    "/tmp/perf-gnunet-datastore-%s",
455                    plugin_name);
456   GNUNET_DISK_directory_remove (dir_name);
457   GNUNET_log_setup ("perf-plugin-datastore",
458 #if VERBOSE
459                     "DEBUG",
460 #else
461                     "WARNING",
462 #endif
463                     NULL);
464   ret = check ();
465   if (pos != plugin_name)
466     pos[0] = '.';
467   GNUNET_DISK_directory_remove (dir_name);
468
469   return ret;
470 }
471
472 /* end of perf_plugin_datastore.c */
473
474