collision detection for IBF, timing for test tool
[oweals/gnunet.git] / src / consensus / gnunet-consensus-ibf.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 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 /**
22  * @file consensus/gnunet-consensus-ibf
23  * @brief tool for reconciling data with invertible bloom filters
24  * @author Florian Dold
25  */
26
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_container_lib.h"
31 #include "gnunet_util_lib.h"
32
33 #include "ibf.h"
34
35 static unsigned int asize = 10;
36 static unsigned int bsize = 10;
37 static unsigned int csize = 10;
38 static unsigned int hash_num = 3;
39 static unsigned int ibf_size = 80;
40
41
42 static struct GNUNET_CONTAINER_MultiHashMap *set_a;
43 static struct GNUNET_CONTAINER_MultiHashMap *set_b;
44 /* common elements in a and b */
45 static struct GNUNET_CONTAINER_MultiHashMap *set_c;
46
47 static struct InvertibleBloomFilter *ibf_a;
48 static struct InvertibleBloomFilter *ibf_b;
49
50
51
52 static int
53 insert_iterator (void *cls,
54                  const struct GNUNET_HashCode *key,
55                  void *value)
56 {
57   struct InvertibleBloomFilter *ibf = (struct InvertibleBloomFilter *) cls;
58   ibf_insert (ibf, key);
59   return GNUNET_YES;
60 }
61
62
63 static void
64 run (void *cls, char *const *args, const char *cfgfile,
65      const struct GNUNET_CONFIGURATION_Handle *cfg)
66 {
67   struct GNUNET_HashCode id;
68   int i;
69   int side;
70   int res;
71   struct GNUNET_TIME_Absolute start_time;
72   struct GNUNET_TIME_Relative delta_time;
73
74   set_a = GNUNET_CONTAINER_multihashmap_create (((asize == 0) ? 1 : (asize + csize)),
75                                                  GNUNET_NO);
76   set_b = GNUNET_CONTAINER_multihashmap_create (((bsize == 0) ? 1 : (bsize + csize)),
77                                                 GNUNET_NO);
78   set_c = GNUNET_CONTAINER_multihashmap_create (((csize == 0) ? 1 : csize),
79                                                 GNUNET_NO);
80
81   printf ("hash-num=%u, size=%u, #(A-B)=%u, #(B-A)=%u, #(A&B)=%u\n",
82           hash_num, ibf_size, asize, bsize, csize);
83
84   i = 0;
85   while (i < asize)
86   {
87     GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id);
88     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
89       continue;
90     GNUNET_CONTAINER_multihashmap_put (
91         set_a, &id, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
92     i++;
93   }
94   i = 0;
95   while (i < bsize)
96   {
97     GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id);
98     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
99       continue;
100     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id))
101       continue;
102     GNUNET_CONTAINER_multihashmap_put (
103         set_b, &id, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
104     i++;
105   }
106   i = 0;
107   while (i < csize)
108   {
109     GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id);
110     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_a, &id))
111       continue;
112     if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (set_b, &id))
113       continue;
114     GNUNET_CONTAINER_multihashmap_put (
115         set_c, &id, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
116     i++;
117   }
118
119   ibf_a = ibf_create (ibf_size, hash_num, 0);
120   ibf_b = ibf_create (ibf_size, hash_num, 0);
121
122   start_time = GNUNET_TIME_absolute_get ();
123
124   GNUNET_CONTAINER_multihashmap_iterate (set_a, &insert_iterator, ibf_a);
125   GNUNET_CONTAINER_multihashmap_iterate (set_b, &insert_iterator, ibf_b);
126   GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_a);
127   GNUNET_CONTAINER_multihashmap_iterate (set_c, &insert_iterator, ibf_b);
128
129   delta_time = GNUNET_TIME_absolute_get_duration (start_time);
130
131   printf ("encoded in: %s\n", GNUNET_STRINGS_relative_time_to_string (delta_time, GNUNET_NO));
132
133   ibf_subtract (ibf_a, ibf_b);
134
135
136   start_time = GNUNET_TIME_absolute_get ();
137
138   for (;;)
139   {
140     res = ibf_decode (ibf_a, &side, &id);
141     if (GNUNET_SYSERR == res) 
142     {
143       printf ("decode failed\n");
144       return;
145     }
146     if (GNUNET_NO == res)
147     {
148       if ((0 == GNUNET_CONTAINER_multihashmap_size (set_b)) &&
149           (0 == GNUNET_CONTAINER_multihashmap_size (set_a)))
150       {
151         delta_time = GNUNET_TIME_absolute_get_duration (start_time);
152         printf ("decoded successfully in: %s\n", GNUNET_STRINGS_relative_time_to_string (delta_time, GNUNET_NO));
153       }
154       else
155         printf ("decode missed elements\n");
156       return;
157     }
158
159     if (side == 1)
160       res = GNUNET_CONTAINER_multihashmap_remove (set_a, &id, NULL);
161     if (side == -1)
162       res = GNUNET_CONTAINER_multihashmap_remove (set_b, &id, NULL);
163     if (GNUNET_YES != res)
164     {
165       printf ("decoded wrong element\n");
166       return;
167     }
168   }
169 }
170
171 int
172 main (int argc, char **argv)
173 {
174   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
175     {'A', "asize", NULL,
176      gettext_noop ("number of element in set A-B"), 1,
177      &GNUNET_GETOPT_set_uint, &asize},
178     {'B', "bsize", NULL,
179      gettext_noop ("number of element in set B-A"), 1,
180      &GNUNET_GETOPT_set_uint, &bsize},
181     {'C', "csize", NULL,
182      gettext_noop ("number of common elements in A and B"), 1,
183      &GNUNET_GETOPT_set_uint, &csize},
184     {'k', "hash-num", NULL,
185      gettext_noop ("hash num"), 1,
186      &GNUNET_GETOPT_set_uint, &hash_num},
187     {'s', "ibf-size", NULL,
188      gettext_noop ("ibf size"), 1,
189      &GNUNET_GETOPT_set_uint, &ibf_size},
190     GNUNET_GETOPT_OPTION_END
191   };
192   GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-ibf",
193                       "help",
194                       options, &run, NULL, GNUNET_YES);
195   return 0;
196 }
197