add option to create identity from private key
[oweals/gnunet.git] / src / namestore / perf_namestore_api_zone_iteration.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file namestore/perf_namestore_api_zone_iteration.c
22  * @brief testcase for zone iteration functionality: iterate all zones
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_namestore_service.h"
27 #include "gnunet_testing_lib.h"
28 #include "namestore.h"
29 #include "gnunet_dnsparser_lib.h"
30
31 #define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT
32
33 /**
34  * A #BENCHMARK_SIZE of 1000 takes less than a minute on a reasonably
35  * modern system, so 30 minutes should be OK even for very, very
36  * slow systems.
37  */
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
39
40 /**
41  * The runtime of the benchmark is expected to be linear
42  * for the iteration phase with a *good* database.  The FLAT
43  * database uses a quadratic retrieval algorithm,
44  * hence it should be quadratic in the size.
45  */
46 #define BENCHMARK_SIZE 1000
47
48 /**
49  * Maximum record size
50  */
51 #define MAX_REC_SIZE 500
52
53 /**
54  * How big are the blocks we fetch? Note that the first block is
55  * always just 1 record set per current API.  Smaller block
56  * sizes will make quadratic iteration-by-offset penalties
57  * more pronounced.
58  */
59 #define BLOCK_SIZE 100
60
61 static struct GNUNET_NAMESTORE_Handle *nsh;
62
63 static struct GNUNET_SCHEDULER_Task *timeout_task;
64
65 static struct GNUNET_SCHEDULER_Task *t;
66
67 static struct GNUNET_CRYPTO_EcdsaPrivateKey privkey;
68
69 static struct GNUNET_NAMESTORE_ZoneIterator *zi;
70
71 static struct GNUNET_NAMESTORE_QueueEntry *qe;
72
73 static int res;
74
75 static unsigned int off;
76
77 static unsigned int left_until_next;
78
79 static uint8_t seen[1 + BENCHMARK_SIZE / 8];
80
81 static struct GNUNET_TIME_Absolute start;
82
83
84 /**
85  * Terminate everything
86  *
87  * @param cls NULL
88  */
89 static void
90 end (void *cls)
91 {
92   (void) cls;
93   if (NULL != qe)
94   {
95     GNUNET_NAMESTORE_cancel (qe);
96     qe = NULL;
97   }
98   if (NULL != zi)
99   {
100     GNUNET_NAMESTORE_zone_iteration_stop (zi);
101     zi = NULL;
102   }
103   if (NULL != nsh)
104   {
105     GNUNET_NAMESTORE_disconnect (nsh);
106     nsh = NULL;
107   }
108   if (NULL != t)
109   {
110     GNUNET_SCHEDULER_cancel (t);
111     t = NULL;
112   }
113   if (NULL != timeout_task)
114   {
115     GNUNET_SCHEDULER_cancel (timeout_task);
116     timeout_task = NULL;
117   }
118 }
119
120
121 /**
122  * End with timeout. As this is a benchmark, we do not
123  * fail hard but return "skipped".
124  */
125 static void
126 timeout (void *cls)
127 {
128   (void) cls;
129   timeout_task = NULL;
130   GNUNET_SCHEDULER_shutdown ();
131   res = 77;
132 }
133
134
135 static struct GNUNET_GNSRECORD_Data *
136 create_record (unsigned int count)
137 {
138   struct GNUNET_GNSRECORD_Data *rd;
139
140   rd = GNUNET_malloc (count + sizeof(struct GNUNET_GNSRECORD_Data));
141   rd->expiration_time = GNUNET_TIME_relative_to_absolute (
142     GNUNET_TIME_UNIT_HOURS).abs_value_us;
143   rd->record_type = TEST_RECORD_TYPE;
144   rd->data_size = count;
145   rd->data = (void *) &rd[1];
146   rd->flags = 0;
147   memset (&rd[1],
148           'a',
149           count);
150   return rd;
151 }
152
153
154 static void
155 zone_end (void *cls)
156 {
157   struct GNUNET_TIME_Relative delay;
158
159   zi = NULL;
160   delay = GNUNET_TIME_absolute_get_duration (start);
161   fprintf (stdout,
162            "Iterating over %u records took %s\n",
163            off,
164            GNUNET_STRINGS_relative_time_to_string (delay,
165                                                    GNUNET_YES));
166   if (BENCHMARK_SIZE == off)
167   {
168     res = 0;
169   }
170   else
171   {
172     GNUNET_break (0);
173     res = 1;
174   }
175   GNUNET_SCHEDULER_shutdown ();
176 }
177
178
179 static void
180 fail_cb (void *cls)
181 {
182   zi = NULL;
183   res = 2;
184   GNUNET_break (0);
185   GNUNET_SCHEDULER_shutdown ();
186 }
187
188
189 static void
190 zone_proc (void *cls,
191            const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
192            const char *label,
193            unsigned int rd_count,
194            const struct GNUNET_GNSRECORD_Data *rd)
195 {
196   struct GNUNET_GNSRECORD_Data *wrd;
197   unsigned int xoff;
198
199   GNUNET_assert (NULL != zone);
200   if (1 != sscanf (label,
201                    "l%u",
202                    &xoff))
203   {
204     res = 3;
205     GNUNET_break (0);
206     GNUNET_SCHEDULER_shutdown ();
207     return;
208   }
209   if ((xoff > BENCHMARK_SIZE) ||
210       (0 != (seen[xoff / 8] & (1U << (xoff % 8)))))
211   {
212     res = 3;
213     GNUNET_break (0);
214     GNUNET_SCHEDULER_shutdown ();
215     return;
216   }
217   seen[xoff / 8] |= (1U << (xoff % 8));
218   wrd = create_record (xoff % MAX_REC_SIZE);
219   if ((rd->record_type != wrd->record_type) ||
220       (rd->data_size != wrd->data_size) ||
221       (rd->flags != wrd->flags))
222   {
223     res = 4;
224     GNUNET_break (0);
225     GNUNET_SCHEDULER_shutdown ();
226     GNUNET_free (wrd);
227     return;
228   }
229   if (0 != memcmp (rd->data,
230                    wrd->data,
231                    wrd->data_size))
232   {
233     res = 4;
234     GNUNET_break (0);
235     GNUNET_SCHEDULER_shutdown ();
236     GNUNET_free (wrd);
237     return;
238   }
239   GNUNET_free (wrd);
240   if (0 != GNUNET_memcmp (zone,
241                           &privkey))
242   {
243     res = 5;
244     GNUNET_break (0);
245     GNUNET_SCHEDULER_shutdown ();
246     return;
247   }
248   off++;
249   left_until_next--;
250   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251               "Obtained record %u, expecting %u more until asking for mor explicitly\n",
252               off,
253               left_until_next);
254   if (0 == left_until_next)
255   {
256     left_until_next = BLOCK_SIZE;
257     GNUNET_NAMESTORE_zone_iterator_next (zi,
258                                          left_until_next);
259   }
260 }
261
262
263 static void
264 publish_record (void *cls);
265
266
267 static void
268 put_cont (void *cls,
269           int32_t success,
270           const char *emsg)
271 {
272   (void) cls;
273   qe = NULL;
274   if (GNUNET_OK != success)
275   {
276     GNUNET_break (0);
277     GNUNET_SCHEDULER_shutdown ();
278     return;
279   }
280   t = GNUNET_SCHEDULER_add_now (&publish_record,
281                                 NULL);
282 }
283
284
285 static void
286 publish_record (void *cls)
287 {
288   struct GNUNET_GNSRECORD_Data *rd;
289   char *label;
290
291   (void) cls;
292   t = NULL;
293   if (BENCHMARK_SIZE == off)
294   {
295     struct GNUNET_TIME_Relative delay;
296
297     delay = GNUNET_TIME_absolute_get_duration (start);
298     fprintf (stdout,
299              "Inserting %u records took %s\n",
300              off,
301              GNUNET_STRINGS_relative_time_to_string (delay,
302                                                      GNUNET_YES));
303     start = GNUNET_TIME_absolute_get ();
304     off = 0;
305     left_until_next = 1;
306     zi = GNUNET_NAMESTORE_zone_iteration_start (nsh,
307                                                 NULL,
308                                                 &fail_cb,
309                                                 NULL,
310                                                 &zone_proc,
311                                                 NULL,
312                                                 &zone_end,
313                                                 NULL);
314     GNUNET_assert (NULL != zi);
315     return;
316   }
317   rd = create_record ((++off) % MAX_REC_SIZE);
318   GNUNET_asprintf (&label,
319                    "l%u",
320                    off);
321   qe = GNUNET_NAMESTORE_records_store (nsh,
322                                        &privkey,
323                                        label,
324                                        1, rd,
325                                        &put_cont,
326                                        NULL);
327   GNUNET_free (label);
328   GNUNET_free (rd);
329 }
330
331
332 static void
333 run (void *cls,
334      const struct GNUNET_CONFIGURATION_Handle *cfg,
335      struct GNUNET_TESTING_Peer *peer)
336 {
337   GNUNET_SCHEDULER_add_shutdown (&end,
338                                  NULL);
339   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
340                                                &timeout,
341                                                NULL);
342   nsh = GNUNET_NAMESTORE_connect (cfg);
343   GNUNET_assert (NULL != nsh);
344   GNUNET_CRYPTO_ecdsa_key_create (&privkey);
345   start = GNUNET_TIME_absolute_get ();
346   t = GNUNET_SCHEDULER_add_now (&publish_record,
347                                 NULL);
348 }
349
350
351 #include "test_common.c"
352
353
354 int
355 main (int argc,
356       char *argv[])
357 {
358   const char *plugin_name;
359   char *cfg_name;
360
361   SETUP_CFG (plugin_name, cfg_name);
362   res = 1;
363   if (0 !=
364       GNUNET_TESTING_peer_run ("perf-namestore-api-zone-iteration",
365                                cfg_name,
366                                &run,
367                                NULL))
368   {
369     res = 1;
370   }
371   GNUNET_DISK_purge_cfg_dir (cfg_name,
372                              "GNUNET_TEST_HOME");
373   GNUNET_free (cfg_name);
374   return res;
375 }
376
377
378 /* end of perf_namestore_api_zone_iteration.c */