gnunet-service-set_union_strata_estimator.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2012 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file set/gnunet-service-set_union_strata_estimator.c
  18. * @brief invertible bloom filter
  19. * @author Florian Dold
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "ibf.h"
  25. #include "gnunet-service-set_union_strata_estimator.h"
  26. /**
  27. * Should we try compressing the strata estimator? This will
  28. * break compatibility with the 0.10.1-network.
  29. */
  30. #define FAIL_10_1_COMPATIBILTIY 1
  31. /**
  32. * Write the given strata estimator to the buffer.
  33. *
  34. * @param se strata estimator to serialize
  35. * @param[out] buf buffer to write to, must be of appropriate size
  36. * @return number of bytes written to @a buf
  37. */
  38. size_t
  39. strata_estimator_write (const struct StrataEstimator *se,
  40. void *buf)
  41. {
  42. char *sbuf = buf;
  43. unsigned int i;
  44. size_t osize;
  45. GNUNET_assert (NULL != se);
  46. for (i = 0; i < se->strata_count; i++)
  47. {
  48. ibf_write_slice (se->strata[i],
  49. 0,
  50. se->ibf_size,
  51. &sbuf[se->ibf_size * IBF_BUCKET_SIZE * i]);
  52. }
  53. osize = se->ibf_size * IBF_BUCKET_SIZE * se->strata_count;
  54. #if FAIL_10_1_COMPATIBILTIY
  55. {
  56. char *cbuf;
  57. size_t nsize;
  58. if (GNUNET_YES ==
  59. GNUNET_try_compression (buf,
  60. osize,
  61. &cbuf,
  62. &nsize))
  63. {
  64. GNUNET_memcpy (buf, cbuf, nsize);
  65. osize = nsize;
  66. GNUNET_free (cbuf);
  67. }
  68. }
  69. #endif
  70. return osize;
  71. }
  72. /**
  73. * Read strata from the buffer into the given strata
  74. * estimator. The strata estimator must already be allocated.
  75. *
  76. * @param buf buffer to read from
  77. * @param buf_len number of bytes in @a buf
  78. * @param is_compressed is the data compressed?
  79. * @param[out] se strata estimator to write to
  80. * @return #GNUNET_OK on success
  81. */
  82. int
  83. strata_estimator_read (const void *buf,
  84. size_t buf_len,
  85. int is_compressed,
  86. struct StrataEstimator *se)
  87. {
  88. unsigned int i;
  89. size_t osize;
  90. char *dbuf;
  91. dbuf = NULL;
  92. if (GNUNET_YES == is_compressed)
  93. {
  94. osize = se->ibf_size * IBF_BUCKET_SIZE * se->strata_count;
  95. dbuf = GNUNET_decompress (buf,
  96. buf_len,
  97. osize);
  98. if (NULL == dbuf)
  99. {
  100. GNUNET_break_op (0); /* bad compressed input data */
  101. return GNUNET_SYSERR;
  102. }
  103. buf = dbuf;
  104. buf_len = osize;
  105. }
  106. if (buf_len != se->strata_count * se->ibf_size * IBF_BUCKET_SIZE)
  107. {
  108. GNUNET_break (0); /* very odd error */
  109. GNUNET_free_non_null (dbuf);
  110. return GNUNET_SYSERR;
  111. }
  112. for (i = 0; i < se->strata_count; i++)
  113. {
  114. ibf_read_slice (buf, 0, se->ibf_size, se->strata[i]);
  115. buf += se->ibf_size * IBF_BUCKET_SIZE;
  116. }
  117. GNUNET_free_non_null (dbuf);
  118. return GNUNET_OK;
  119. }
  120. /**
  121. * Add a key to the strata estimator.
  122. *
  123. * @param se strata estimator to add the key to
  124. * @param key key to add
  125. */
  126. void
  127. strata_estimator_insert (struct StrataEstimator *se,
  128. struct IBF_Key key)
  129. {
  130. uint64_t v;
  131. unsigned int i;
  132. v = key.key_val;
  133. /* count trailing '1'-bits of v */
  134. for (i = 0; v & 1; v>>=1, i++)
  135. /* empty */;
  136. ibf_insert (se->strata[i], key);
  137. }
  138. /**
  139. * Remove a key from the strata estimator.
  140. *
  141. * @param se strata estimator to remove the key from
  142. * @param key key to remove
  143. */
  144. void
  145. strata_estimator_remove (struct StrataEstimator *se,
  146. struct IBF_Key key)
  147. {
  148. uint64_t v;
  149. unsigned int i;
  150. v = key.key_val;
  151. /* count trailing '1'-bits of v */
  152. for (i = 0; v & 1; v>>=1, i++)
  153. /* empty */;
  154. ibf_remove (se->strata[i], key);
  155. }
  156. /**
  157. * Create a new strata estimator with the given parameters.
  158. *
  159. * @param strata_count number of stratas, that is, number of ibfs in the estimator
  160. * @param ibf_size size of each ibf stratum
  161. * @param ibf_hashnum hashnum parameter of each ibf
  162. * @return a freshly allocated, empty strata estimator, NULL on error
  163. */
  164. struct StrataEstimator *
  165. strata_estimator_create (unsigned int strata_count,
  166. uint32_t ibf_size,
  167. uint8_t ibf_hashnum)
  168. {
  169. struct StrataEstimator *se;
  170. unsigned int i;
  171. unsigned int j;
  172. se = GNUNET_new (struct StrataEstimator);
  173. se->strata_count = strata_count;
  174. se->ibf_size = ibf_size;
  175. se->strata = GNUNET_new_array (strata_count,
  176. struct InvertibleBloomFilter *);
  177. for (i = 0; i < strata_count; i++)
  178. {
  179. se->strata[i] = ibf_create (ibf_size, ibf_hashnum);
  180. if (NULL == se->strata[i])
  181. {
  182. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  183. "Failed to allocate memory for strata estimator\n");
  184. for (j = 0; j < i; j++)
  185. ibf_destroy (se->strata[i]);
  186. GNUNET_free (se);
  187. return NULL;
  188. }
  189. }
  190. return se;
  191. }
  192. /**
  193. * Estimate set difference with two strata estimators,
  194. * i.e. arrays of IBFs.
  195. * Does not not modify its arguments.
  196. *
  197. * @param se1 first strata estimator
  198. * @param se2 second strata estimator
  199. * @return the estimated difference
  200. */
  201. unsigned int
  202. strata_estimator_difference (const struct StrataEstimator *se1,
  203. const struct StrataEstimator *se2)
  204. {
  205. unsigned int count;
  206. GNUNET_assert (se1->strata_count == se2->strata_count);
  207. count = 0;
  208. for (int i = se1->strata_count - 1; i >= 0; i--)
  209. {
  210. struct InvertibleBloomFilter *diff;
  211. /* number of keys decoded from the ibf */
  212. /* FIXME: implement this without always allocating new IBFs */
  213. diff = ibf_dup (se1->strata[i]);
  214. ibf_subtract (diff, se2->strata[i]);
  215. for (int ibf_count = 0; GNUNET_YES; ibf_count++)
  216. {
  217. int more;
  218. more = ibf_decode (diff, NULL, NULL);
  219. if (GNUNET_NO == more)
  220. {
  221. count += ibf_count;
  222. break;
  223. }
  224. /* Estimate if decoding fails or would not terminate */
  225. if ((GNUNET_SYSERR == more) || (ibf_count > diff->size))
  226. {
  227. ibf_destroy (diff);
  228. return count * (1 << (i + 1));
  229. }
  230. }
  231. ibf_destroy (diff);
  232. }
  233. return count;
  234. }
  235. /**
  236. * Make a copy of a strata estimator.
  237. *
  238. * @param se the strata estimator to copy
  239. * @return the copy
  240. */
  241. struct StrataEstimator *
  242. strata_estimator_dup (struct StrataEstimator *se)
  243. {
  244. struct StrataEstimator *c;
  245. unsigned int i;
  246. c = GNUNET_new (struct StrataEstimator);
  247. c->strata_count = se->strata_count;
  248. c->ibf_size = se->ibf_size;
  249. c->strata = GNUNET_new_array (se->strata_count,
  250. struct InvertibleBloomFilter *);
  251. for (i = 0; i < se->strata_count; i++)
  252. c->strata[i] = ibf_dup (se->strata[i]);
  253. return c;
  254. }
  255. /**
  256. * Destroy a strata estimator, free all of its resources.
  257. *
  258. * @param se strata estimator to destroy.
  259. */
  260. void
  261. strata_estimator_destroy (struct StrataEstimator *se)
  262. {
  263. unsigned int i;
  264. for (i = 0; i < se->strata_count; i++)
  265. ibf_destroy (se->strata[i]);
  266. GNUNET_free (se->strata);
  267. GNUNET_free (se);
  268. }