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