f1fa53e01c8fdc6bf9eff44e311a5fcd06932561
[oweals/gnunet.git] / src / rps / gnunet-service-rps_sampler.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C)
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 rps/gnunet-service-rps_sampler.c
23  * @brief sampler implementation
24  * @author Julius Bünger
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "rps.h"
29
30 #include "gnunet-service-rps_sampler.h"
31
32 #include <math.h>
33 #include <inttypes.h>
34
35 #define LOG(kind, ...) GNUNET_log_from(kind,"rps-sampler",__VA_ARGS__)
36
37 // multiple 'clients'?
38
39 // TODO check for overflows
40
41 // TODO align message structs
42
43 // hist_size_init, hist_size_max
44
45 /***********************************************************************
46  * WARNING: This section needs to be reviewed regarding the use of
47  * functions providing (pseudo)randomness!
48 ***********************************************************************/
49
50 // TODO care about invalid input of the caller (size 0 or less...)
51
52 enum RPS_SamplerEmpty
53 {
54   NOT_EMPTY = 0x0,
55       EMPTY = 0x1
56 };
57
58 /**
59  * A sampler element sampling one PeerID at a time.
60  */
61 struct RPS_SamplerElement
62 {
63   /**
64    * Min-wise linear permutation used by this sampler.
65    *
66    * This is an key later used by a hmac.
67    */
68   struct GNUNET_CRYPTO_AuthKey auth_key;
69
70   /**
71    * The PeerID this sampler currently samples.
72    */
73   struct GNUNET_PeerIdentity peer_id;
74
75   /**
76    * The according hash value of this PeerID.
77    */
78   struct GNUNET_HashCode peer_id_hash;
79
80
81   /**
82    * Time of last request.
83    */
84   struct GNUNET_TIME_Absolute last_client_request;
85
86   /**
87    * Flag that indicates that we are not holding a valid PeerID right now.
88    */
89   enum RPS_SamplerEmpty is_empty;
90
91   /**
92    * 'Birth'
93    */
94   struct GNUNET_TIME_Absolute birth;
95
96   /**
97    * How many times a PeerID was put in this sampler.
98    */
99   uint32_t num_peers;
100
101   /**
102    * How many times this sampler changed the peer_id.
103    */
104   uint32_t num_change;
105 };
106
107
108 /**
109  * Sampler with its own array of SamplerElements
110  */
111 struct RPS_Sampler
112 {
113   /**
114    * Number of sampler elements we hold.
115    */
116   unsigned int sampler_size;
117   //size_t size;
118
119   /**
120    * All Samplers in one array.
121    */
122   struct RPS_SamplerElement **sampler_elements;
123
124   /**
125    * Max time a round takes
126    *
127    * Used in the context of RPS
128    */
129   struct GNUNET_TIME_Relative max_round_interval;
130 };
131
132 /**
133  * Closure to _get_n_rand_peers_ready_cb()
134  */
135 struct NRandPeersReadyCls
136 {
137   /**
138    * Number of peers we are waiting for.
139    */
140   uint32_t num_peers;
141
142   /**
143    * Number of peers we currently have.
144    */
145   uint32_t cur_num_peers;
146
147   /**
148    * Pointer to the array holding the ids.
149    */
150   struct GNUNET_PeerIdentity *ids;
151
152   /**
153    * Callback to be called when all ids are available.
154    */
155   RPS_sampler_n_rand_peers_ready_cb callback;
156
157   /**
158    * Closure given to the callback
159    */
160   void *cls;
161 };
162
163 /**
164  * Callback that is called from _get_rand_peer() when the PeerID is ready.
165  *
166  * @param cls the closure given alongside this function.
167  * @param id the PeerID that was returned
168  */
169 typedef void
170 (*RPS_sampler_rand_peer_ready_cont) (void *cls,
171         const struct GNUNET_PeerIdentity *id);
172
173 /**
174  * Closure for #sampler_get_rand_peer()
175  */
176 struct GetPeerCls
177 {
178   /**
179    * DLL
180    */
181   struct GetPeerCls *next;
182
183   /**
184    * DLL
185    */
186   struct GetPeerCls *prev;
187
188   /**
189    * The sampler this function operates on.
190    */
191   struct RPS_Sampler *sampler;
192
193   /**
194    * The task for this function.
195    */
196   struct GNUNET_SCHEDULER_Task *get_peer_task;
197
198   /**
199    * The callback
200    */
201   RPS_sampler_rand_peer_ready_cont cont;
202
203   /**
204    * The closure to the callback @e cont
205    */
206   void *cont_cls;
207
208   /**
209    * The address of the id to be stored at
210    */
211   struct GNUNET_PeerIdentity *id;
212 };
213
214
215 ///**
216 // * Global sampler variable.
217 // */
218 //struct RPS_Sampler *sampler;
219
220
221 /**
222  * The minimal size for the extended sampler elements.
223  */
224 static size_t min_size;
225
226 /**
227  * The maximal size the extended sampler elements should grow to.
228  */
229 static size_t max_size;
230
231 /**
232  * The size the extended sampler elements currently have.
233  */
234 //static size_t extra_size;
235
236 /**
237  * Inedex to the sampler element that is the next to be returned
238  */
239 static uint32_t client_get_index;
240
241
242 /** FIXME document */
243 static struct GetPeerCls *gpc_head;
244 static struct GetPeerCls *gpc_tail;
245
246
247 /**
248  * Callback to _get_rand_peer() used by _get_n_rand_peers().
249  *
250  * Checks whether all n peers are available. If they are,
251  * give those back.
252  */
253 static void
254 check_n_peers_ready (void *cls,
255     const struct GNUNET_PeerIdentity *id)
256 {
257   struct NRandPeersReadyCls *n_peers_cls = cls;
258
259   n_peers_cls->cur_num_peers++;
260   LOG (GNUNET_ERROR_TYPE_DEBUG,
261       "Got %" PRIX32 ". of %" PRIX32 " peers\n",
262       n_peers_cls->cur_num_peers, n_peers_cls->num_peers);
263
264   if (n_peers_cls->num_peers == n_peers_cls->cur_num_peers)
265   { /* All peers are ready -- return those to the client */
266     GNUNET_assert (NULL != n_peers_cls->callback);
267
268     LOG (GNUNET_ERROR_TYPE_DEBUG,
269         "returning %" PRIX32 " peers to the client\n",
270         n_peers_cls->num_peers);
271     n_peers_cls->callback (n_peers_cls->cls, n_peers_cls->ids, n_peers_cls->num_peers);
272
273     GNUNET_free (n_peers_cls);
274   }
275 }
276
277
278 /**
279  * Reinitialise a previously initialised sampler element.
280  *
281  * @param sampler pointer to the memory that keeps the value.
282  */
283   static void
284 RPS_sampler_elem_reinit (struct RPS_SamplerElement *sampler_el)
285 {
286   sampler_el->is_empty = EMPTY;
287
288   // I guess I don't need to call GNUNET_CRYPTO_hmac_derive_key()...
289   GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_STRONG,
290                              &(sampler_el->auth_key.key),
291                              GNUNET_CRYPTO_HASH_LENGTH);
292
293   sampler_el->last_client_request = GNUNET_TIME_UNIT_FOREVER_ABS;
294
295   sampler_el->birth = GNUNET_TIME_absolute_get ();
296   sampler_el->num_peers = 0;
297   sampler_el->num_change = 0;
298 }
299
300
301 /**
302  * (Re)Initialise given Sampler with random min-wise independent function.
303  *
304  * In this implementation this means choosing an auth_key for later use in
305  * a hmac at random.
306  *
307  * @return a newly created RPS_SamplerElement which currently holds no id.
308  */
309   struct RPS_SamplerElement *
310 RPS_sampler_elem_create (void)
311 {
312   struct RPS_SamplerElement *s;
313
314   s = GNUNET_new (struct RPS_SamplerElement);
315
316   RPS_sampler_elem_reinit (s);
317
318   return s;
319 }
320
321
322 /**
323  * Input an PeerID into the given sampler element.
324  *
325  * @param sampler the sampler the @a s_elem belongs to.
326  *                Needed to know the
327  */
328 static void
329 RPS_sampler_elem_next (struct RPS_SamplerElement *s_elem,
330                        struct RPS_Sampler *sampler,
331                        const struct GNUNET_PeerIdentity *other)
332 {
333   struct GNUNET_HashCode other_hash;
334
335   s_elem->num_peers++;
336
337   if (0 == GNUNET_CRYPTO_cmp_peer_identity (other, &(s_elem->peer_id)))
338   {
339     LOG (GNUNET_ERROR_TYPE_DEBUG, "         Got PeerID %s\n",
340         GNUNET_i2s (other));
341     LOG (GNUNET_ERROR_TYPE_DEBUG, "Have already PeerID %s\n",
342         GNUNET_i2s (&(s_elem->peer_id)));
343   }
344   else
345   {
346     GNUNET_CRYPTO_hmac(&s_elem->auth_key,
347         other,
348         sizeof(struct GNUNET_PeerIdentity),
349         &other_hash);
350
351     if (EMPTY == s_elem->is_empty)
352     {
353       LOG (GNUNET_ERROR_TYPE_DEBUG,
354            "Got PeerID %s; Simply accepting (was empty previously).\n",
355            GNUNET_i2s(other));
356       s_elem->peer_id = *other;
357       s_elem->peer_id_hash = other_hash;
358
359       s_elem->num_change++;
360     }
361     else if (0 > GNUNET_CRYPTO_hash_cmp (&other_hash, &s_elem->peer_id_hash))
362     {
363       LOG (GNUNET_ERROR_TYPE_DEBUG, "           Got PeerID %s\n",
364           GNUNET_i2s (other));
365       LOG (GNUNET_ERROR_TYPE_DEBUG, "Discarding old PeerID %s\n",
366           GNUNET_i2s (&s_elem->peer_id));
367
368       s_elem->num_change++;
369     }
370     else
371     {
372       LOG (GNUNET_ERROR_TYPE_DEBUG, "        Got PeerID %s\n",
373           GNUNET_i2s (other));
374       LOG (GNUNET_ERROR_TYPE_DEBUG, "Keeping old PeerID %s\n",
375           GNUNET_i2s (&s_elem->peer_id));
376     }
377   }
378   s_elem->is_empty = NOT_EMPTY;
379 }
380
381
382 /**
383  * Get the size of the sampler.
384  *
385  * @param sampler the sampler to return the size of.
386  * @return the size of the sampler
387  */
388 unsigned int
389 RPS_sampler_get_size (struct RPS_Sampler *sampler)
390 {
391   return sampler->sampler_size;
392 }
393
394
395 /**
396  * Grow or shrink the size of the sampler.
397  *
398  * @param sampler the sampler to resize.
399  * @param new_size the new size of the sampler
400  */
401 static void
402 sampler_resize (struct RPS_Sampler *sampler, unsigned int new_size)
403 {
404   unsigned int old_size;
405   uint32_t i;
406
407   // TODO check min and max size
408
409   old_size = sampler->sampler_size;
410
411   if (old_size > new_size)
412   { /* Shrinking */
413     /* Temporary store those to properly call the removeCB on those later */
414
415     LOG (GNUNET_ERROR_TYPE_DEBUG, "Shrinking sampler %d -> %d\n", old_size, new_size);
416     GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, new_size);
417     LOG (GNUNET_ERROR_TYPE_DEBUG,
418         "sampler->sampler_elements now points to %p\n",
419         sampler->sampler_elements);
420
421   }
422   else if (old_size < new_size)
423   { /* Growing */
424     LOG (GNUNET_ERROR_TYPE_DEBUG, "Growing sampler %d -> %d\n", old_size, new_size);
425     GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, new_size);
426
427     for ( i = old_size ; i < new_size ; i++ )
428     { /* Add new sampler elements */
429       sampler->sampler_elements[i] = RPS_sampler_elem_create ();
430     }
431   }
432   else
433   {
434     LOG (GNUNET_ERROR_TYPE_DEBUG, "Size remains the same -- nothing to do\n");
435     return;
436   }
437
438   GNUNET_assert (sampler->sampler_size == new_size);
439 }
440
441
442 /**
443  * Grow or shrink the size of the sampler.
444  *
445  * @param sampler the sampler to resize.
446  * @param new_size the new size of the sampler
447  */
448 void
449 RPS_sampler_resize (struct RPS_Sampler *sampler, unsigned int new_size)
450 {
451   GNUNET_assert (0 < new_size);
452   sampler_resize (sampler, new_size);
453 }
454
455
456 /**
457  * Empty the sampler.
458  *
459  * @param sampler the sampler to empty.
460  * @param new_size the new size of the sampler
461  */
462 static void
463 sampler_empty (struct RPS_Sampler *sampler)
464 {
465   sampler_resize (sampler, 0);
466 }
467
468
469 /**
470  * Initialise a tuple of sampler elements.
471  *
472  * @param init_size the size the sampler is initialised with
473  * @param ins_cb the callback that will be called on every PeerID that is
474  *               newly inserted into a sampler element
475  * @param ins_cls the closure given to #ins_cb
476  * @param rem_cb the callback that will be called on every PeerID that is
477  *               removed from a sampler element
478  * @param rem_cls the closure given to #rem_cb
479  * @return a handle to a sampler that consists of sampler elements.
480  */
481 struct RPS_Sampler *
482 RPS_sampler_init (size_t init_size,
483     struct GNUNET_TIME_Relative max_round_interval)
484 {
485   struct RPS_Sampler *sampler;
486   //uint32_t i;
487
488   /* Initialise context around extended sampler */
489   min_size = 10; // TODO make input to _samplers_init()
490   max_size = 1000; // TODO make input to _samplers_init()
491
492   sampler = GNUNET_new (struct RPS_Sampler);
493   sampler->sampler_size = 0;
494   sampler->sampler_elements = NULL;
495   sampler->max_round_interval = max_round_interval;
496   //sampler->sampler_elements = GNUNET_new_array(init_size, struct GNUNET_PeerIdentity);
497   //GNUNET_array_grow (sampler->sampler_elements, sampler->sampler_size, min_size);
498   RPS_sampler_resize (sampler, init_size);
499
500   client_get_index = 0;
501
502   //GNUNET_assert (init_size == sampler->sampler_size);
503   return sampler;
504 }
505
506
507 /**
508  * A fuction to update every sampler in the given list
509  *
510  * @param sampler the sampler to update.
511  * @param id the PeerID that is put in the sampler
512  */
513   void
514 RPS_sampler_update (struct RPS_Sampler *sampler,
515                     const struct GNUNET_PeerIdentity *id)
516 {
517   uint32_t i;
518
519   for ( i = 0 ; i < sampler->sampler_size ; i++ )
520     RPS_sampler_elem_next (sampler->sampler_elements[i],
521                            sampler,
522                            id);
523 }
524
525
526 /**
527  * Reinitialise all previously initialised sampler elements with the given value.
528  *
529  * Used to get rid of a PeerID.
530  *
531  * @param sampler the sampler to reinitialise a sampler element in.
532  * @param id the id of the sampler elements to update.
533  */
534   void
535 RPS_sampler_reinitialise_by_value (struct RPS_Sampler *sampler,
536                                    const struct GNUNET_PeerIdentity *id)
537 {
538   uint32_t i;
539
540   for ( i = 0 ; i < sampler->sampler_size ; i++ )
541   {
542     if ( 0 == GNUNET_CRYPTO_cmp_peer_identity(id, &(sampler->sampler_elements[i]->peer_id)) )
543     {
544       LOG (GNUNET_ERROR_TYPE_DEBUG, "Reinitialising sampler\n");
545       RPS_sampler_elem_reinit (sampler->sampler_elements[i]);
546     }
547   }
548 }
549
550
551 /**
552  * Get one random peer out of the sampled peers.
553  *
554  * We might want to reinitialise this sampler after giving the
555  * corrsponding peer to the client.
556  * Only used internally
557  */
558 static void
559 sampler_get_rand_peer2 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
560 {
561   struct GetPeerCls *gpc = cls;
562   uint32_t r_index;
563
564   gpc->get_peer_task = NULL;
565   GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, gpc);
566   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
567     return;
568
569   /**;
570    * Choose the r_index of the peer we want to return
571    * at random from the interval of the gossip list
572    */
573   r_index = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
574       gpc->sampler->sampler_size);
575
576   if ( EMPTY == gpc->sampler->sampler_elements[r_index]->is_empty )
577   {
578     gpc->get_peer_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
579                                                                    GNUNET_TIME_UNIT_SECONDS,
580                                                                    .1),
581                                                        &sampler_get_rand_peer2,
582                                                        cls);
583     return;
584   }
585
586   *gpc->id = gpc->sampler->sampler_elements[r_index]->peer_id;
587
588   gpc->cont (gpc->cont_cls, gpc->id);
589   GNUNET_free (gpc);
590 }
591
592
593 /**
594  * Get one random peer out of the sampled peers.
595  *
596  * We might want to reinitialise this sampler after giving the
597  * corrsponding peer to the client.
598  */
599 static void
600 sampler_get_rand_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
601 {
602   struct GetPeerCls *gpc = cls;
603   struct GNUNET_PeerIdentity tmp_id;
604   unsigned int empty_flag;
605   struct RPS_SamplerElement *s_elem;
606   struct GNUNET_TIME_Relative last_request_diff;
607   uint32_t tmp_client_get_index;
608
609   gpc->get_peer_task = NULL;
610   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
611     return;
612
613   LOG (GNUNET_ERROR_TYPE_DEBUG, "Single peer was requested\n");
614
615
616   /* Store the next #client_get_index to check whether we cycled over the whole list */
617   if (0 < client_get_index)
618     tmp_client_get_index = client_get_index - 1;
619   else
620     tmp_client_get_index = gpc->sampler->sampler_size - 1;
621
622   LOG (GNUNET_ERROR_TYPE_DEBUG,
623       "sched for later if index reaches %" PRIX32 " (sampler size: %" PRIX32 ").\n",
624       tmp_client_get_index, gpc->sampler->sampler_size);
625
626   do
627   { /* Get first non empty sampler */
628     if (tmp_client_get_index == client_get_index)
629     { /* We once cycled over the whole list */
630       LOG (GNUNET_ERROR_TYPE_DEBUG, "reached tmp_index %" PRIX32 ".\n",
631            client_get_index);
632       GNUNET_assert (NULL == gpc->get_peer_task);
633       gpc->get_peer_task =
634         GNUNET_SCHEDULER_add_delayed (gpc->sampler->max_round_interval,
635                                       &sampler_get_rand_peer,
636                                       cls);
637       return;
638     }
639
640     tmp_id = gpc->sampler->sampler_elements[client_get_index]->peer_id;
641     empty_flag = gpc->sampler->sampler_elements[client_get_index]->is_empty;
642     RPS_sampler_elem_reinit (gpc->sampler->sampler_elements[client_get_index]);
643     if (EMPTY != empty_flag)
644       RPS_sampler_elem_next (gpc->sampler->sampler_elements[client_get_index],
645                              gpc->sampler,
646                              &tmp_id);
647
648     /* Cycle the #client_get_index one step further */
649     if ( client_get_index == gpc->sampler->sampler_size - 1 )
650       client_get_index = 0;
651     else
652       client_get_index++;
653
654     LOG (GNUNET_ERROR_TYPE_DEBUG, "incremented index to %" PRIX32 ".\n",
655          client_get_index);
656   } while (EMPTY == gpc->sampler->sampler_elements[client_get_index]->is_empty);
657
658   s_elem = gpc->sampler->sampler_elements[client_get_index];
659   *gpc->id = s_elem->peer_id;
660
661   /* Check whether we may use this sampler to give it back to the client */
662   if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != s_elem->last_client_request.abs_value_us)
663   {
664     last_request_diff =
665       GNUNET_TIME_absolute_get_difference (s_elem->last_client_request,
666                                            GNUNET_TIME_absolute_get ());
667     /* We're not going to give it back now if it was
668      * already requested by a client this round */
669     if (last_request_diff.rel_value_us < gpc->sampler->max_round_interval.rel_value_us)
670     {
671       LOG (GNUNET_ERROR_TYPE_DEBUG,
672           "Last client request on this sampler was less than max round interval ago -- scheduling for later\n");
673       ///* How many time remains untile the next round has started? */
674       //inv_last_request_diff =
675       //  GNUNET_TIME_absolute_get_difference (last_request_diff,
676       //                                       sampler->max_round_interval);
677       // add a little delay
678       /* Schedule it one round later */
679       GNUNET_assert (NULL == gpc->get_peer_task);
680       gpc->get_peer_task =
681         GNUNET_SCHEDULER_add_delayed (gpc->sampler->max_round_interval,
682                                       &sampler_get_rand_peer,
683                                       cls);
684       return;
685     }
686     // TODO add other reasons to wait here
687   }
688
689   s_elem->last_client_request = GNUNET_TIME_absolute_get ();
690
691   GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, gpc);
692   gpc->cont (gpc->cont_cls, gpc->id);
693   GNUNET_free (gpc);
694 }
695
696
697 /**
698  * Get n random peers out of the sampled peers.
699  *
700  * We might want to reinitialise this sampler after giving the
701  * corrsponding peer to the client.
702  * Random with or without consumption?
703  *
704  * @param sampler the sampler to get peers from.
705  * @param cb callback that will be called once the ids are ready.
706  * @param cls closure given to @a cb
707  * @param for_client #GNUNET_YES if result is used for client,
708  *                   #GNUNET_NO if used internally
709  * @param num_peers the number of peers requested
710  */
711   void
712 RPS_sampler_get_n_rand_peers (struct RPS_Sampler *sampler,
713                               RPS_sampler_n_rand_peers_ready_cb cb,
714                               void *cls, uint32_t num_peers, int for_client)
715 {
716   GNUNET_assert (0 != sampler->sampler_size);
717
718   // TODO check if we have too much (distinct) sampled peers
719   uint32_t i;
720   struct NRandPeersReadyCls *cb_cls;
721   struct GetPeerCls *gpc;
722
723   cb_cls = GNUNET_new (struct NRandPeersReadyCls);
724   cb_cls->num_peers = num_peers;
725   cb_cls->cur_num_peers = 0;
726   cb_cls->ids = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
727   cb_cls->callback = cb;
728   cb_cls->cls = cls;
729
730   LOG (GNUNET_ERROR_TYPE_DEBUG,
731       "Scheduling requests for %" PRIX32 " peers\n", num_peers);
732
733   for ( i = 0 ; i < num_peers ; i++ )
734   {
735     gpc = GNUNET_new (struct GetPeerCls);
736     gpc->sampler = sampler;
737     gpc->cont = check_n_peers_ready;
738     gpc->cont_cls = cb_cls;
739     gpc->id = &cb_cls->ids[i];
740
741     // maybe add a little delay
742     if (GNUNET_YES == for_client)
743       gpc->get_peer_task = GNUNET_SCHEDULER_add_now (&sampler_get_rand_peer, gpc);
744     else if (GNUNET_NO == for_client)
745       gpc->get_peer_task = GNUNET_SCHEDULER_add_now (&sampler_get_rand_peer2, gpc);
746     else
747       GNUNET_assert (0);
748
749     GNUNET_CONTAINER_DLL_insert (gpc_head, gpc_tail, gpc);
750   }
751 }
752
753
754 /**
755  * Counts how many Samplers currently hold a given PeerID.
756  *
757  * @param sampler the sampler to count ids in.
758  * @param id the PeerID to count.
759  *
760  * @return the number of occurrences of id.
761  */
762   uint32_t
763 RPS_sampler_count_id (struct RPS_Sampler *sampler,
764                       const struct GNUNET_PeerIdentity *id)
765 {
766   uint32_t count;
767   uint32_t i;
768
769   count = 0;
770   for ( i = 0 ; i < sampler->sampler_size ; i++ )
771   {
772     if ( 0 == GNUNET_CRYPTO_cmp_peer_identity (&sampler->sampler_elements[i]->peer_id, id)
773         && EMPTY != sampler->sampler_elements[i]->is_empty)
774       count++;
775   }
776   return count;
777 }
778
779
780 /**
781  * Cleans the sampler.
782  */
783   void
784 RPS_sampler_destroy (struct RPS_Sampler *sampler)
785 {
786   struct GetPeerCls *i;
787
788   for (i = gpc_head; NULL != i; i = gpc_head)
789   {
790     GNUNET_CONTAINER_DLL_remove (gpc_head, gpc_tail, i);
791     GNUNET_SCHEDULER_cancel (i->get_peer_task);
792     GNUNET_free (i);
793   }
794
795   sampler_empty (sampler);
796   GNUNET_free (sampler);
797 }
798
799 /* end of gnunet-service-rps.c */