diff options
Diffstat (limited to 'src/setu/gnunet-service-setu_strata_estimator.c')
-rw-r--r-- | src/setu/gnunet-service-setu_strata_estimator.c | 362 |
1 files changed, 268 insertions, 94 deletions
diff --git a/src/setu/gnunet-service-setu_strata_estimator.c b/src/setu/gnunet-service-setu_strata_estimator.c index 7c9a4deb6..7981cc847 100644 --- a/src/setu/gnunet-service-setu_strata_estimator.c +++ b/src/setu/gnunet-service-setu_strata_estimator.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * @brief invertible bloom filter | 22 | * @brief invertible bloom filter |
23 | * @author Florian Dold | 23 | * @author Florian Dold |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * @author Elias Summermatter | ||
25 | */ | 26 | */ |
26 | #include "platform.h" | 27 | #include "platform.h" |
27 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
@@ -30,6 +31,82 @@ | |||
30 | 31 | ||
31 | 32 | ||
32 | /** | 33 | /** |
34 | * Should we try compressing the strata estimator? This will | ||
35 | * break compatibility with the 0.10.1-network. | ||
36 | */ | ||
37 | #define FAIL_10_1_COMPATIBILTIY 1 | ||
38 | |||
39 | /** | ||
40 | * Number of strata estimators in memory NOT transmitted | ||
41 | */ | ||
42 | |||
43 | #define MULTI_SE_BASE_COUNT 8 | ||
44 | |||
45 | /** | ||
46 | * The avg size of 1 se | ||
47 | * Based on the bsc thesis of Elias Summermatter (2021) | ||
48 | */ | ||
49 | |||
50 | #define AVG_BYTE_SIZE_SE 4221 | ||
51 | |||
52 | /** | ||
53 | * Calculates the optimal number of strata Estimators to send | ||
54 | * @param avg_element_size | ||
55 | * @param element_count | ||
56 | * @return | ||
57 | */ | ||
58 | uint8_t | ||
59 | determine_strata_count (uint64_t avg_element_size, uint64_t element_count) | ||
60 | { | ||
61 | uint64_t base_size = avg_element_size * element_count; | ||
62 | /* >67kb total size of elements in set */ | ||
63 | if (base_size < AVG_BYTE_SIZE_SE * 16) | ||
64 | return 1; | ||
65 | /* >270kb total size of elements in set */ | ||
66 | if (base_size < AVG_BYTE_SIZE_SE * 64) | ||
67 | return 2; | ||
68 | /* >1mb total size of elements in set */ | ||
69 | if (base_size < AVG_BYTE_SIZE_SE * 256) | ||
70 | return 4; | ||
71 | return 8; | ||
72 | } | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Modify an IBF key @a k_in based on the @a salt, returning a | ||
77 | * salted key in @a k_out. | ||
78 | */ | ||
79 | static void | ||
80 | salt_key (const struct IBF_Key *k_in, | ||
81 | uint32_t salt, | ||
82 | struct IBF_Key *k_out) | ||
83 | { | ||
84 | int s = (salt * 7) % 64; | ||
85 | uint64_t x = k_in->key_val; | ||
86 | |||
87 | /* rotate ibf key */ | ||
88 | x = (x >> s) | (x << (64 - s)); | ||
89 | k_out->key_val = x; | ||
90 | } | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Reverse modification done in the salt_key function | ||
95 | */ | ||
96 | static void | ||
97 | unsalt_key (const struct IBF_Key *k_in, | ||
98 | uint32_t salt, | ||
99 | struct IBF_Key *k_out) | ||
100 | { | ||
101 | int s = (salt * 7) % 64; | ||
102 | uint64_t x = k_in->key_val; | ||
103 | |||
104 | x = (x << s) | (x >> (64 - s)); | ||
105 | k_out->key_val = x; | ||
106 | } | ||
107 | |||
108 | |||
109 | /** | ||
33 | * Write the given strata estimator to the buffer. | 110 | * Write the given strata estimator to the buffer. |
34 | * | 111 | * |
35 | * @param se strata estimator to serialize | 112 | * @param se strata estimator to serialize |
@@ -37,21 +114,33 @@ | |||
37 | * @return number of bytes written to @a buf | 114 | * @return number of bytes written to @a buf |
38 | */ | 115 | */ |
39 | size_t | 116 | size_t |
40 | strata_estimator_write (const struct StrataEstimator *se, | 117 | strata_estimator_write (struct MultiStrataEstimator *se, |
118 | uint16_t se_ibf_total_size, | ||
119 | uint8_t number_se_send, | ||
41 | void *buf) | 120 | void *buf) |
42 | { | 121 | { |
43 | char *sbuf = buf; | 122 | char *sbuf = buf; |
123 | unsigned int i; | ||
44 | size_t osize; | 124 | size_t osize; |
125 | uint64_t sbuf_offset = 0; | ||
126 | se->size = number_se_send; | ||
45 | 127 | ||
46 | GNUNET_assert (NULL != se); | 128 | GNUNET_assert (NULL != se); |
47 | for (unsigned int i = 0; i < se->strata_count; i++) | 129 | for (uint8_t strata_ctr = 0; strata_ctr < number_se_send; strata_ctr++) |
48 | { | 130 | { |
49 | ibf_write_slice (se->strata[i], | 131 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) |
50 | 0, | 132 | { |
51 | se->ibf_size, | 133 | ibf_write_slice (se->stratas[strata_ctr]->strata[i], |
52 | &sbuf[se->ibf_size * IBF_BUCKET_SIZE * i]); | 134 | 0, |
135 | se->stratas[strata_ctr]->ibf_size, | ||
136 | &sbuf[sbuf_offset], | ||
137 | 8); | ||
138 | sbuf_offset += se->stratas[strata_ctr]->ibf_size * IBF_BUCKET_SIZE; | ||
139 | } | ||
53 | } | 140 | } |
54 | osize = se->ibf_size * IBF_BUCKET_SIZE * se->strata_count; | 141 | osize = ((se_ibf_total_size / 8) * number_se_send) * IBF_BUCKET_SIZE |
142 | * se->stratas[0]->strata_count; | ||
143 | #if FAIL_10_1_COMPATIBILTIY | ||
55 | { | 144 | { |
56 | char *cbuf; | 145 | char *cbuf; |
57 | size_t nsize; | 146 | size_t nsize; |
@@ -62,13 +151,12 @@ strata_estimator_write (const struct StrataEstimator *se, | |||
62 | &cbuf, | 151 | &cbuf, |
63 | &nsize)) | 152 | &nsize)) |
64 | { | 153 | { |
65 | GNUNET_memcpy (buf, | 154 | GNUNET_memcpy (buf, cbuf, nsize); |
66 | cbuf, | ||
67 | nsize); | ||
68 | osize = nsize; | 155 | osize = nsize; |
69 | GNUNET_free (cbuf); | 156 | GNUNET_free (cbuf); |
70 | } | 157 | } |
71 | } | 158 | } |
159 | #endif | ||
72 | return osize; | 160 | return osize; |
73 | } | 161 | } |
74 | 162 | ||
@@ -87,15 +175,19 @@ int | |||
87 | strata_estimator_read (const void *buf, | 175 | strata_estimator_read (const void *buf, |
88 | size_t buf_len, | 176 | size_t buf_len, |
89 | int is_compressed, | 177 | int is_compressed, |
90 | struct StrataEstimator *se) | 178 | uint8_t number_se_received, |
179 | uint16_t se_ibf_total_size, | ||
180 | struct MultiStrataEstimator *se) | ||
91 | { | 181 | { |
182 | unsigned int i; | ||
92 | size_t osize; | 183 | size_t osize; |
93 | char *dbuf; | 184 | char *dbuf; |
94 | 185 | ||
95 | dbuf = NULL; | 186 | dbuf = NULL; |
96 | if (GNUNET_YES == is_compressed) | 187 | if (GNUNET_YES == is_compressed) |
97 | { | 188 | { |
98 | osize = se->ibf_size * IBF_BUCKET_SIZE * se->strata_count; | 189 | osize = ((se_ibf_total_size / 8) * number_se_received) * IBF_BUCKET_SIZE |
190 | * se->stratas[0]->strata_count; | ||
99 | dbuf = GNUNET_decompress (buf, | 191 | dbuf = GNUNET_decompress (buf, |
100 | buf_len, | 192 | buf_len, |
101 | osize); | 193 | osize); |
@@ -108,18 +200,25 @@ strata_estimator_read (const void *buf, | |||
108 | buf_len = osize; | 200 | buf_len = osize; |
109 | } | 201 | } |
110 | 202 | ||
111 | if (buf_len != se->strata_count * se->ibf_size * IBF_BUCKET_SIZE) | 203 | if (buf_len != se->stratas[0]->strata_count * ((se_ibf_total_size / 8) |
204 | * number_se_received) | ||
205 | * IBF_BUCKET_SIZE) | ||
112 | { | 206 | { |
113 | GNUNET_break (0); /* very odd error */ | 207 | GNUNET_break (0); /* very odd error */ |
114 | GNUNET_free (dbuf); | 208 | GNUNET_free (dbuf); |
115 | return GNUNET_SYSERR; | 209 | return GNUNET_SYSERR; |
116 | } | 210 | } |
117 | 211 | ||
118 | for (unsigned int i = 0; i < se->strata_count; i++) | 212 | for (uint8_t strata_ctr = 0; strata_ctr < number_se_received; strata_ctr++) |
119 | { | 213 | { |
120 | ibf_read_slice (buf, 0, se->ibf_size, se->strata[i]); | 214 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) |
121 | buf += se->ibf_size * IBF_BUCKET_SIZE; | 215 | { |
216 | ibf_read_slice (buf, 0, se->stratas[strata_ctr]->ibf_size, | ||
217 | se->stratas[strata_ctr]->strata[i], 8); | ||
218 | buf += se->stratas[strata_ctr]->ibf_size * IBF_BUCKET_SIZE; | ||
219 | } | ||
122 | } | 220 | } |
221 | se->size = number_se_received; | ||
123 | GNUNET_free (dbuf); | 222 | GNUNET_free (dbuf); |
124 | return GNUNET_OK; | 223 | return GNUNET_OK; |
125 | } | 224 | } |
@@ -132,38 +231,61 @@ strata_estimator_read (const void *buf, | |||
132 | * @param key key to add | 231 | * @param key key to add |
133 | */ | 232 | */ |
134 | void | 233 | void |
135 | strata_estimator_insert (struct StrataEstimator *se, | 234 | strata_estimator_insert (struct MultiStrataEstimator *se, |
136 | struct IBF_Key key) | 235 | struct IBF_Key key) |
137 | { | 236 | { |
138 | uint64_t v; | ||
139 | unsigned int i; | ||
140 | 237 | ||
141 | v = key.key_val; | 238 | |
142 | /* count trailing '1'-bits of v */ | 239 | /* count trailing '1'-bits of v */ |
143 | for (i = 0; v & 1; v >>= 1, i++) | 240 | for (int strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) |
144 | /* empty */; | 241 | { |
145 | ibf_insert (se->strata[i], key); | 242 | unsigned int i; |
243 | uint64_t v; | ||
244 | |||
245 | struct IBF_Key salted_key; | ||
246 | salt_key (&key, | ||
247 | strata_ctr * (64 / MULTI_SE_BASE_COUNT), | ||
248 | &salted_key); | ||
249 | v = salted_key.key_val; | ||
250 | for (i = 0; v & 1; v >>= 1, i++) | ||
251 | { | ||
252 | ibf_insert (se->stratas[strata_ctr]->strata[i], salted_key); | ||
253 | } | ||
254 | } | ||
255 | /* empty */; | ||
256 | |||
146 | } | 257 | } |
147 | 258 | ||
148 | 259 | ||
149 | /** | 260 | /** |
150 | * Remove a key from the strata estimator. | 261 | * Remove a key from the strata estimator. (NOT USED) |
151 | * | 262 | * |
152 | * @param se strata estimator to remove the key from | 263 | * @param se strata estimator to remove the key from |
153 | * @param key key to remove | 264 | * @param key key to remove |
154 | */ | 265 | */ |
155 | void | 266 | void |
156 | strata_estimator_remove (struct StrataEstimator *se, | 267 | strata_estimator_remove (struct MultiStrataEstimator *se, |
157 | struct IBF_Key key) | 268 | struct IBF_Key key) |
158 | { | 269 | { |
159 | uint64_t v; | ||
160 | unsigned int i; | ||
161 | 270 | ||
162 | v = key.key_val; | ||
163 | /* count trailing '1'-bits of v */ | 271 | /* count trailing '1'-bits of v */ |
164 | for (i = 0; v & 1; v >>= 1, i++) | 272 | for (int strata_ctr = 0; strata_ctr < se->size; strata_ctr++) |
165 | /* empty */; | 273 | { |
166 | ibf_remove (se->strata[i], key); | 274 | uint64_t v; |
275 | unsigned int i; | ||
276 | |||
277 | struct IBF_Key unsalted_key; | ||
278 | unsalt_key (&key, | ||
279 | strata_ctr * (64 / MULTI_SE_BASE_COUNT), | ||
280 | &unsalted_key); | ||
281 | |||
282 | v = unsalted_key.key_val; | ||
283 | for (i = 0; v & 1; v >>= 1, i++) | ||
284 | { | ||
285 | /* empty */; | ||
286 | ibf_remove (se->stratas[strata_ctr]->strata[i], unsalted_key); | ||
287 | } | ||
288 | } | ||
167 | } | 289 | } |
168 | 290 | ||
169 | 291 | ||
@@ -175,29 +297,42 @@ strata_estimator_remove (struct StrataEstimator *se, | |||
175 | * @param ibf_hashnum hashnum parameter of each ibf | 297 | * @param ibf_hashnum hashnum parameter of each ibf |
176 | * @return a freshly allocated, empty strata estimator, NULL on error | 298 | * @return a freshly allocated, empty strata estimator, NULL on error |
177 | */ | 299 | */ |
178 | struct StrataEstimator * | 300 | struct MultiStrataEstimator * |
179 | strata_estimator_create (unsigned int strata_count, | 301 | strata_estimator_create (unsigned int strata_count, |
180 | uint32_t ibf_size, | 302 | uint32_t ibf_size, |
181 | uint8_t ibf_hashnum) | 303 | uint8_t ibf_hashnum) |
182 | { | 304 | { |
183 | struct StrataEstimator *se; | 305 | struct MultiStrataEstimator *se; |
184 | 306 | unsigned int i; | |
185 | se = GNUNET_new (struct StrataEstimator); | 307 | unsigned int j; |
186 | se->strata_count = strata_count; | 308 | se = GNUNET_new (struct MultiStrataEstimator); |
187 | se->ibf_size = ibf_size; | 309 | |
188 | se->strata = GNUNET_new_array (strata_count, | 310 | se->size = MULTI_SE_BASE_COUNT; |
189 | struct InvertibleBloomFilter *); | 311 | se->stratas = GNUNET_new_array (MULTI_SE_BASE_COUNT,struct StrataEstimator *); |
190 | for (unsigned int i = 0; i < strata_count; i++) | 312 | |
313 | uint8_t ibf_prime_sizes[] = {79,79,79,79,79,79,79,79}; | ||
314 | |||
315 | for (uint8_t strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) | ||
191 | { | 316 | { |
192 | se->strata[i] = ibf_create (ibf_size, ibf_hashnum); | 317 | se->stratas[strata_ctr] = GNUNET_new (struct StrataEstimator); |
193 | if (NULL == se->strata[i]) | 318 | se->stratas[strata_ctr]->strata_count = strata_count; |
319 | se->stratas[strata_ctr]->ibf_size = ibf_prime_sizes[strata_ctr]; | ||
320 | se->stratas[strata_ctr]->strata = GNUNET_new_array (strata_count * 4, | ||
321 | struct | ||
322 | InvertibleBloomFilter *); | ||
323 | for (i = 0; i < strata_count; i++) | ||
194 | { | 324 | { |
195 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 325 | se->stratas[strata_ctr]->strata[i] = ibf_create ( |
196 | "Failed to allocate memory for strata estimator\n"); | 326 | ibf_prime_sizes[strata_ctr], ibf_hashnum); |
197 | for (unsigned int j = 0; j < i; j++) | 327 | if (NULL == se->stratas[strata_ctr]->strata[i]) |
198 | ibf_destroy (se->strata[i]); | 328 | { |
199 | GNUNET_free (se); | 329 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
200 | return NULL; | 330 | "Failed to allocate memory for strata estimator\n"); |
331 | for (j = 0; j < i; j++) | ||
332 | ibf_destroy (se->stratas[strata_ctr]->strata[i]); | ||
333 | GNUNET_free (se); | ||
334 | return NULL; | ||
335 | } | ||
201 | } | 336 | } |
202 | } | 337 | } |
203 | return se; | 338 | return se; |
@@ -213,46 +348,71 @@ strata_estimator_create (unsigned int strata_count, | |||
213 | * @param se2 second strata estimator | 348 | * @param se2 second strata estimator |
214 | * @return the estimated difference | 349 | * @return the estimated difference |
215 | */ | 350 | */ |
216 | unsigned int | 351 | void |
217 | strata_estimator_difference (const struct StrataEstimator *se1, | 352 | strata_estimator_difference (const struct MultiStrataEstimator *se1, |
218 | const struct StrataEstimator *se2) | 353 | const struct MultiStrataEstimator *se2) |
219 | { | 354 | { |
220 | unsigned int count; | 355 | int avg_local_diff = 0; |
356 | int avg_remote_diff = 0; | ||
357 | uint8_t number_of_estimators = se1->size; | ||
221 | 358 | ||
222 | GNUNET_assert (se1->strata_count == se2->strata_count); | 359 | for (uint8_t strata_ctr = 0; strata_ctr < number_of_estimators; strata_ctr++) |
223 | count = 0; | ||
224 | for (int i = se1->strata_count - 1; i >= 0; i--) | ||
225 | { | 360 | { |
226 | struct InvertibleBloomFilter *diff; | 361 | GNUNET_assert (se1->stratas[strata_ctr]->strata_count == |
227 | /* number of keys decoded from the ibf */ | 362 | se2->stratas[strata_ctr]->strata_count); |
228 | 363 | ||
229 | /* FIXME: implement this without always allocating new IBFs */ | 364 | |
230 | diff = ibf_dup (se1->strata[i]); | 365 | for (int i = se1->stratas[strata_ctr]->strata_count - 1; i >= 0; i--) |
231 | ibf_subtract (diff, | ||
232 | se2->strata[i]); | ||
233 | for (int ibf_count = 0; GNUNET_YES; ibf_count++) | ||
234 | { | 366 | { |
235 | int more; | 367 | struct InvertibleBloomFilter *diff; |
368 | /* number of keys decoded from the ibf */ | ||
236 | 369 | ||
237 | more = ibf_decode (diff, | 370 | /* FIXME: implement this without always allocating new IBFs */ |
238 | NULL, | 371 | diff = ibf_dup (se1->stratas[strata_ctr]->strata[i]); |
239 | NULL); | 372 | diff->local_decoded_count = 0; |
240 | if (GNUNET_NO == more) | 373 | diff->remote_decoded_count = 0; |
241 | { | 374 | |
242 | count += ibf_count; | 375 | ibf_subtract (diff, se2->stratas[strata_ctr]->strata[i]); |
243 | break; | 376 | |
244 | } | 377 | for (int ibf_count = 0; GNUNET_YES; ibf_count++) |
245 | /* Estimate if decoding fails or would not terminate */ | ||
246 | if ( (GNUNET_SYSERR == more) || | ||
247 | (ibf_count > diff->size) ) | ||
248 | { | 378 | { |
249 | ibf_destroy (diff); | 379 | int more; |
250 | return count * (1 << (i + 1)); | 380 | |
381 | more = ibf_decode (diff, NULL, NULL); | ||
382 | if (GNUNET_NO == more) | ||
383 | { | ||
384 | se1->stratas[strata_ctr]->strata[0]->local_decoded_count += | ||
385 | diff->local_decoded_count; | ||
386 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count += | ||
387 | diff->remote_decoded_count; | ||
388 | break; | ||
389 | } | ||
390 | /* Estimate if decoding fails or would not terminate */ | ||
391 | if ((GNUNET_SYSERR == more) || (ibf_count > diff->size)) | ||
392 | { | ||
393 | se1->stratas[strata_ctr]->strata[0]->local_decoded_count = | ||
394 | se1->stratas[strata_ctr]->strata[0]->local_decoded_count * (1 << (i | ||
395 | + | ||
396 | 1)); | ||
397 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count = | ||
398 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count * (1 << (i | ||
399 | + | ||
400 | 1)); | ||
401 | ibf_destroy (diff); | ||
402 | goto break_all_counting_loops; | ||
403 | } | ||
251 | } | 404 | } |
405 | ibf_destroy (diff); | ||
252 | } | 406 | } |
253 | ibf_destroy (diff); | 407 | break_all_counting_loops:; |
408 | avg_local_diff += se1->stratas[strata_ctr]->strata[0]->local_decoded_count; | ||
409 | avg_remote_diff += | ||
410 | se1->stratas[strata_ctr]->strata[0]->remote_decoded_count; | ||
254 | } | 411 | } |
255 | return count; | 412 | se1->stratas[0]->strata[0]->local_decoded_count = avg_local_diff |
413 | / number_of_estimators; | ||
414 | se1->stratas[0]->strata[0]->remote_decoded_count = avg_remote_diff | ||
415 | / number_of_estimators; | ||
256 | } | 416 | } |
257 | 417 | ||
258 | 418 | ||
@@ -262,18 +422,28 @@ strata_estimator_difference (const struct StrataEstimator *se1, | |||
262 | * @param se the strata estimator to copy | 422 | * @param se the strata estimator to copy |
263 | * @return the copy | 423 | * @return the copy |
264 | */ | 424 | */ |
265 | struct StrataEstimator * | 425 | struct MultiStrataEstimator * |
266 | strata_estimator_dup (struct StrataEstimator *se) | 426 | strata_estimator_dup (struct MultiStrataEstimator *se) |
267 | { | 427 | { |
268 | struct StrataEstimator *c; | 428 | struct MultiStrataEstimator *c; |
269 | 429 | unsigned int i; | |
270 | c = GNUNET_new (struct StrataEstimator); | 430 | |
271 | c->strata_count = se->strata_count; | 431 | c = GNUNET_new (struct MultiStrataEstimator); |
272 | c->ibf_size = se->ibf_size; | 432 | c->stratas = GNUNET_new_array (MULTI_SE_BASE_COUNT,struct StrataEstimator *); |
273 | c->strata = GNUNET_new_array (se->strata_count, | 433 | for (uint8_t strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) |
274 | struct InvertibleBloomFilter *); | 434 | { |
275 | for (unsigned int i = 0; i < se->strata_count; i++) | 435 | c->stratas[strata_ctr] = GNUNET_new (struct StrataEstimator); |
276 | c->strata[i] = ibf_dup (se->strata[i]); | 436 | c->stratas[strata_ctr]->strata_count = |
437 | se->stratas[strata_ctr]->strata_count; | ||
438 | c->stratas[strata_ctr]->ibf_size = se->stratas[strata_ctr]->ibf_size; | ||
439 | c->stratas[strata_ctr]->strata = GNUNET_new_array ( | ||
440 | se->stratas[strata_ctr]->strata_count, | ||
441 | struct | ||
442 | InvertibleBloomFilter *); | ||
443 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) | ||
444 | c->stratas[strata_ctr]->strata[i] = ibf_dup ( | ||
445 | se->stratas[strata_ctr]->strata[i]); | ||
446 | } | ||
277 | return c; | 447 | return c; |
278 | } | 448 | } |
279 | 449 | ||
@@ -284,10 +454,14 @@ strata_estimator_dup (struct StrataEstimator *se) | |||
284 | * @param se strata estimator to destroy. | 454 | * @param se strata estimator to destroy. |
285 | */ | 455 | */ |
286 | void | 456 | void |
287 | strata_estimator_destroy (struct StrataEstimator *se) | 457 | strata_estimator_destroy (struct MultiStrataEstimator *se) |
288 | { | 458 | { |
289 | for (unsigned int i = 0; i < se->strata_count; i++) | 459 | unsigned int i; |
290 | ibf_destroy (se->strata[i]); | 460 | for (uint8_t strata_ctr = 0; strata_ctr < MULTI_SE_BASE_COUNT; strata_ctr++) |
291 | GNUNET_free (se->strata); | 461 | { |
462 | for (i = 0; i < se->stratas[strata_ctr]->strata_count; i++) | ||
463 | ibf_destroy (se->stratas[strata_ctr]->strata[i]); | ||
464 | GNUNET_free (se->stratas[strata_ctr]->strata); | ||
465 | } | ||
292 | GNUNET_free (se); | 466 | GNUNET_free (se); |
293 | } | 467 | } |