2 This file is part of GNUnet
3 Copyright (C) 2012 GNUnet e.V.
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.
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.
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/>.
19 * @file set/gnunet-service-set_union_strata_estimator.c
20 * @brief invertible bloom filter
21 * @author Florian Dold
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
27 #include "gnunet-service-set_union_strata_estimator.h"
31 * Should we try compressing the strata estimator? This will
32 * break compatibility with the 0.10.1-network.
34 #define FAIL_10_1_COMPATIBILTIY 1
38 * Write the given strata estimator to the buffer.
40 * @param se strata estimator to serialize
41 * @param[out] buf buffer to write to, must be of appropriate size
42 * @return number of bytes written to @a buf
45 strata_estimator_write (const struct StrataEstimator *se,
52 GNUNET_assert (NULL != se);
53 for (i = 0; i < se->strata_count; i++)
55 ibf_write_slice (se->strata[i],
58 &sbuf[se->ibf_size * IBF_BUCKET_SIZE * i]);
60 osize = se->ibf_size * IBF_BUCKET_SIZE * se->strata_count;
61 #if FAIL_10_1_COMPATIBILTIY
67 GNUNET_try_compression (buf,
72 GNUNET_memcpy (buf, cbuf, nsize);
83 * Read strata from the buffer into the given strata
84 * estimator. The strata estimator must already be allocated.
86 * @param buf buffer to read from
87 * @param buf_len number of bytes in @a buf
88 * @param is_compressed is the data compressed?
89 * @param[out] se strata estimator to write to
90 * @return #GNUNET_OK on success
93 strata_estimator_read (const void *buf,
96 struct StrataEstimator *se)
103 if (GNUNET_YES == is_compressed)
105 osize = se->ibf_size * IBF_BUCKET_SIZE * se->strata_count;
106 dbuf = GNUNET_decompress (buf,
111 GNUNET_break_op (0); /* bad compressed input data */
112 return GNUNET_SYSERR;
118 if (buf_len != se->strata_count * se->ibf_size * IBF_BUCKET_SIZE)
120 GNUNET_break (0); /* very odd error */
121 GNUNET_free_non_null (dbuf);
122 return GNUNET_SYSERR;
125 for (i = 0; i < se->strata_count; i++)
127 ibf_read_slice (buf, 0, se->ibf_size, se->strata[i]);
128 buf += se->ibf_size * IBF_BUCKET_SIZE;
130 GNUNET_free_non_null (dbuf);
136 * Add a key to the strata estimator.
138 * @param se strata estimator to add the key to
139 * @param key key to add
142 strata_estimator_insert (struct StrataEstimator *se,
149 /* count trailing '1'-bits of v */
150 for (i = 0; v & 1; v>>=1, i++)
152 ibf_insert (se->strata[i], key);
157 * Remove a key from the strata estimator.
159 * @param se strata estimator to remove the key from
160 * @param key key to remove
163 strata_estimator_remove (struct StrataEstimator *se,
170 /* count trailing '1'-bits of v */
171 for (i = 0; v & 1; v>>=1, i++)
173 ibf_remove (se->strata[i], key);
178 * Create a new strata estimator with the given parameters.
180 * @param strata_count number of stratas, that is, number of ibfs in the estimator
181 * @param ibf_size size of each ibf stratum
182 * @param ibf_hashnum hashnum parameter of each ibf
183 * @return a freshly allocated, empty strata estimator, NULL on error
185 struct StrataEstimator *
186 strata_estimator_create (unsigned int strata_count,
190 struct StrataEstimator *se;
194 se = GNUNET_new (struct StrataEstimator);
195 se->strata_count = strata_count;
196 se->ibf_size = ibf_size;
197 se->strata = GNUNET_new_array (strata_count,
198 struct InvertibleBloomFilter *);
199 for (i = 0; i < strata_count; i++)
201 se->strata[i] = ibf_create (ibf_size, ibf_hashnum);
202 if (NULL == se->strata[i])
204 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
205 "Failed to allocate memory for strata estimator\n");
206 for (j = 0; j < i; j++)
207 ibf_destroy (se->strata[i]);
217 * Estimate set difference with two strata estimators,
218 * i.e. arrays of IBFs.
219 * Does not not modify its arguments.
221 * @param se1 first strata estimator
222 * @param se2 second strata estimator
223 * @return the estimated difference
226 strata_estimator_difference (const struct StrataEstimator *se1,
227 const struct StrataEstimator *se2)
231 GNUNET_assert (se1->strata_count == se2->strata_count);
233 for (int i = se1->strata_count - 1; i >= 0; i--)
235 struct InvertibleBloomFilter *diff;
236 /* number of keys decoded from the ibf */
238 /* FIXME: implement this without always allocating new IBFs */
239 diff = ibf_dup (se1->strata[i]);
240 ibf_subtract (diff, se2->strata[i]);
241 for (int ibf_count = 0; GNUNET_YES; ibf_count++)
245 more = ibf_decode (diff, NULL, NULL);
246 if (GNUNET_NO == more)
251 /* Estimate if decoding fails or would not terminate */
252 if ((GNUNET_SYSERR == more) || (ibf_count > diff->size))
255 return count * (1 << (i + 1));
265 * Make a copy of a strata estimator.
267 * @param se the strata estimator to copy
270 struct StrataEstimator *
271 strata_estimator_dup (struct StrataEstimator *se)
273 struct StrataEstimator *c;
276 c = GNUNET_new (struct StrataEstimator);
277 c->strata_count = se->strata_count;
278 c->ibf_size = se->ibf_size;
279 c->strata = GNUNET_new_array (se->strata_count,
280 struct InvertibleBloomFilter *);
281 for (i = 0; i < se->strata_count; i++)
282 c->strata[i] = ibf_dup (se->strata[i]);
288 * Destroy a strata estimator, free all of its resources.
290 * @param se strata estimator to destroy.
293 strata_estimator_destroy (struct StrataEstimator *se)
297 for (i = 0; i < se->strata_count; i++)
298 ibf_destroy (se->strata[i]);
299 GNUNET_free (se->strata);