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