/**
 * Figure out when and how to transmit to the given peer.
 *
 * @param cls the 'struct PeerPlan'
 * @param tc scheduler context
 */
static void
schedule_peer_transmission (void *cls,
                            const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct PeerPlan *pp = cls;
  struct GSF_RequestPlan *rp;
  size_t msize;
  struct GNUNET_TIME_Relative delay;

  pp->task = GNUNET_SCHEDULER_NO_TASK;
  if (NULL != pp->pth)
  {
    GSF_peer_transmit_cancel_ (pp->pth);
    pp->pth = NULL;
  }
  /* move ready requests to priority queue */
  while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) &&
         (GNUNET_TIME_absolute_get_remaining
          (rp->earliest_transmission).rel_value == 0))
  {
    GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap));
    rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority);
  }
  if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap))
  {
    /* priority heap (still) empty, check for delay... */
    rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap);
    if (NULL == rp)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n",
                  pp);
      return;                   /* both queues empty */
    }
    delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Sleeping for %llu ms before retrying requests on plan %p.\n",
                (unsigned long long) delay.rel_value, pp);
    GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout"),
                           delay.rel_value, GNUNET_NO);

    pp->task =
        GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp);
    return;
  }
#if INSANE_STATISTICS
  GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"),
                            1, GNUNET_NO);
#endif
  /* process from priority heap */
  rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp);
  GNUNET_assert (NULL != rp);
  msize = GSF_pending_request_get_message_ (get_latest (rp), 0, NULL);
  pp->pth =
      GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority,
                          GNUNET_TIME_UNIT_FOREVER_REL, msize,
                          &transmit_message_callback, pp);
  GNUNET_assert (NULL != pp->pth);
}
/**
 * Get a random item for expiration.  Call 'proc' with all values ZERO
 * or NULL if the datastore is empty.
 *
 * @param cls closure
 * @param proc function to call the value (once only).
 * @param proc_cls closure for proc
 */
static void
heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
			    void *proc_cls)
{
  struct Plugin *plugin = cls;
  struct Value *value;

  value = GNUNET_CONTAINER_heap_peek (plugin->by_expiration);
  if (NULL == value)
  {
    proc (proc_cls, 
	  NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
    return;
  }
  if (GNUNET_NO ==
      proc (proc_cls, 
	    &value->key,
	    value->size,
	    &value[1],
	    value->type,
	    value->priority,
	    value->anonymity,
	    value->expiration,
	    (uint64_t) (long) value))
    delete_value (plugin, value);
}
/**
 * Function called to get a message for transmission.
 *
 * @param cls closure
 * @param buf_size number of bytes available in buf
 * @param buf where to copy the message, NULL on error (peer disconnect)
 * @return number of bytes copied to 'buf', can be 0 (without indicating an error)
 */
static size_t
transmit_message_callback (void *cls, size_t buf_size, void *buf)
{
  struct PeerPlan *pp = cls;
  struct GSF_RequestPlan *rp;
  size_t msize;

  pp->pth = NULL;
  if (NULL == buf)
  {
    /* failed, try again... */
    if (GNUNET_SCHEDULER_NO_TASK != pp->task)
      GNUNET_SCHEDULER_cancel (pp->task);

    pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp);
    GNUNET_STATISTICS_update (GSF_stats,
                              gettext_noop
                              ("# transmission failed (core has no bandwidth)"),
                              1, GNUNET_NO);
    return 0;
  }
  rp = GNUNET_CONTAINER_heap_peek (pp->priority_heap);
  if (NULL == rp)
  {
    if (GNUNET_SCHEDULER_NO_TASK != pp->task)
      GNUNET_SCHEDULER_cancel (pp->task);
    pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp);
    return 0;
  }
  msize = GSF_pending_request_get_message_ (get_latest (rp), buf_size, buf);
  if (msize > buf_size)
  {
    if (GNUNET_SCHEDULER_NO_TASK != pp->task)
      GNUNET_SCHEDULER_cancel (pp->task);
    /* buffer to small (message changed), try again */
    pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp);
    return 0;
  }
  /* remove from root, add again elsewhere... */
  GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->priority_heap));
  rp->hn = NULL;
  rp->last_transmission = GNUNET_TIME_absolute_get ();
  rp->transmission_counter++;
  total_delay++;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Executing plan %p executed %u times, planning retransmission\n",
              rp, rp->transmission_counter);
  plan (pp, rp);
  GNUNET_STATISTICS_update (GSF_stats,
                            gettext_noop
                            ("# query messages sent to other peers"), 1,
                            GNUNET_NO);
  return msize;
}
/**
 * Remove the oldest entry from the DHT routing table.  Must only
 * be called if it is known that there is at least one entry
 * in the heap and hashmap.
 */
static void
expire_oldest_entry ()
{
  struct RecentRequest *recent_req;

  GNUNET_STATISTICS_update (GDS_stats,
			    gettext_noop
			    ("# Entries removed from routing table"), 1,
			    GNUNET_NO);
  recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
  GNUNET_assert (recent_req != NULL);
  GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
  GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf);
  GNUNET_assert (GNUNET_YES ==
		 GNUNET_CONTAINER_multihashmap_remove (recent_map, 
						       &recent_req->key, 
						       recent_req));
  GNUNET_free (recent_req);
}
static int
check ()
{
  struct GNUNET_CONTAINER_Heap *myHeap;
  struct GNUNET_CONTAINER_HeapNode *n1;
  struct GNUNET_CONTAINER_HeapNode *n2;
  struct GNUNET_CONTAINER_HeapNode *n3;
  struct GNUNET_CONTAINER_HeapNode *n4;
  struct GNUNET_CONTAINER_HeapNode *n5;
  struct GNUNET_CONTAINER_HeapNode *n6;
  struct GNUNET_CONTAINER_HeapNode *n7;
  struct GNUNET_CONTAINER_HeapNode *n8;
  const char *r;

  myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);

  // GNUNET_CONTAINER_heap_remove_root heap empty, taking if-branch
  n1 = GNUNET_CONTAINER_heap_remove_root (myHeap);
  GNUNET_assert (NULL == n1);

  // GNUNET_CONTAINER_heap_peek heap empty, taking if-branch
  n1 = GNUNET_CONTAINER_heap_peek (myHeap);
  GNUNET_assert (NULL == n1);

  // GNUNET_CONTAINER_heap_walk_get_next: heap empty, taking if-branch
  n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_assert (NULL == n1);

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "11", 11);
  GNUNET_assert (NULL != n1);


  // GNUNET_CONTAINER_heap_peek not empty, taking if-branch
  n2 = NULL;
  n2 = GNUNET_CONTAINER_heap_peek (myHeap);
  GNUNET_assert (NULL != n2);

  // GNUNET_CONTAINER_heap_walk_get_next: 1 element
  n1 = NULL;
  n1 = GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_assert (NULL != n1);

  GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);
  GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap));
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "78", 78);
  GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap));
  GNUNET_assert (0 == strcmp ("78", GNUNET_CONTAINER_heap_remove_node (n2)));
  GNUNET_assert (1 == GNUNET_CONTAINER_heap_get_size (myHeap));
  GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);

  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "15", 5);
  GNUNET_CONTAINER_heap_update_cost (myHeap, n3, 15);
  GNUNET_assert (2 == GNUNET_CONTAINER_heap_get_size (myHeap));
  GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);

  n4 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50);
  GNUNET_CONTAINER_heap_update_cost (myHeap, n4, 50);
  GNUNET_assert (3 == GNUNET_CONTAINER_heap_get_size (myHeap));
  GNUNET_CONTAINER_heap_iterate (myHeap, &iterator_callback, NULL);

  n5 = GNUNET_CONTAINER_heap_insert (myHeap, "100", 100);
  n6 = GNUNET_CONTAINER_heap_insert (myHeap, "30/200", 30);
  GNUNET_assert (5 == GNUNET_CONTAINER_heap_get_size (myHeap));
  GNUNET_CONTAINER_heap_remove_node (n5);
  r = GNUNET_CONTAINER_heap_remove_root (myHeap);       /* n1 */
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("11", r));
  GNUNET_CONTAINER_heap_update_cost (myHeap, n6, 200);
  GNUNET_CONTAINER_heap_remove_node (n3);
  r = GNUNET_CONTAINER_heap_remove_root (myHeap);       /* n4 */
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("50", r));
  r = GNUNET_CONTAINER_heap_remove_root (myHeap);       /* n6 */
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("30/200", r));
  GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (myHeap));

  GNUNET_CONTAINER_heap_destroy (myHeap);

  // My additions to a complete testcase
  // Testing a GNUNET_CONTAINER_HEAP_ORDER_MIN
  // Testing remove_node

  myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15);

  r = GNUNET_CONTAINER_heap_remove_node (n1);
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("10", r));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);

  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  r = GNUNET_CONTAINER_heap_remove_node (n2);
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("20", r));
  r = GNUNET_CONTAINER_heap_remove_node (n1);
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("10", r));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);

  GNUNET_CONTAINER_heap_remove_node (n2);
  GNUNET_CONTAINER_heap_remove_node (n1);
  r = GNUNET_CONTAINER_heap_remove_root (myHeap);
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("30", r));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);

  GNUNET_CONTAINER_heap_remove_node (n2);
  GNUNET_CONTAINER_heap_remove_node (n1);
  r = GNUNET_CONTAINER_heap_remove_node (n3);
  GNUNET_assert (NULL != r);
  GNUNET_assert (0 == strcmp ("30", r));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30);

  GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
  GNUNET_assert (0 ==
                 nstrcmp ("10", GNUNET_CONTAINER_heap_remove_root (myHeap)));
  GNUNET_assert (0 ==
                 nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap)));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30);
  n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40);
  n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50);
  n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60);

  // Inserting nodes deeper in the tree with lower costs
  n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10);
  n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10);

  GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3)));

  // Cleaning up...
  GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6)));
  GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5)));

  // Testing heap_walk_get_next
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);;
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);

  GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));
  GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
  GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4)));
  GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7)));
  GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8)));

  // End Testing remove_node

  // Testing a GNUNET_CONTAINER_HEAP_ORDER_MAX
  GNUNET_CONTAINER_heap_destroy (myHeap);

  myHeap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  GNUNET_CONTAINER_heap_update_cost (myHeap, n1, 15);

  GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);

  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
  GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);

  GNUNET_CONTAINER_heap_remove_node (n2);
  GNUNET_CONTAINER_heap_remove_node (n1);
  GNUNET_assert (0 ==
                 nstrcmp ("30", GNUNET_CONTAINER_heap_remove_root (myHeap)));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 10);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 10);

  GNUNET_CONTAINER_heap_remove_node (n2);
  GNUNET_CONTAINER_heap_remove_node (n1);
  GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3)));

  n1 = GNUNET_CONTAINER_heap_insert (myHeap, "10", 10);
  n2 = GNUNET_CONTAINER_heap_insert (myHeap, "20", 20);
  n3 = GNUNET_CONTAINER_heap_insert (myHeap, "30", 30);
  n4 = GNUNET_CONTAINER_heap_insert (myHeap, "40", 40);
  n5 = GNUNET_CONTAINER_heap_insert (myHeap, "50", 50);
  n6 = GNUNET_CONTAINER_heap_insert (myHeap, "60", 60);

  // Inserting nodes deeper in the tree with lower costs
  n7 = GNUNET_CONTAINER_heap_insert (myHeap, "70", 10);
  n8 = GNUNET_CONTAINER_heap_insert (myHeap, "80", 10);

  GNUNET_assert (0 == nstrcmp ("30", GNUNET_CONTAINER_heap_remove_node (n3)));

  // Cleaning up...
  GNUNET_assert (0 == nstrcmp ("60", GNUNET_CONTAINER_heap_remove_node (n6)));
  GNUNET_assert (0 == nstrcmp ("50", GNUNET_CONTAINER_heap_remove_node (n5)));

  // Testing heap_walk_get_next
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);;
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);
  GNUNET_CONTAINER_heap_walk_get_next (myHeap);

  GNUNET_assert (0 == nstrcmp ("10", GNUNET_CONTAINER_heap_remove_node (n1)));
  GNUNET_assert (0 == nstrcmp ("20", GNUNET_CONTAINER_heap_remove_node (n2)));
  GNUNET_assert (0 == nstrcmp ("40", GNUNET_CONTAINER_heap_remove_node (n4)));
  GNUNET_assert (0 == nstrcmp ("70", GNUNET_CONTAINER_heap_remove_node (n7)));
  GNUNET_assert (0 == nstrcmp ("80", GNUNET_CONTAINER_heap_remove_node (n8)));

  // End Testing remove_node

  GNUNET_CONTAINER_heap_destroy (myHeap);

  return 0;
}
Exemple #6
0
/**
 * Figure out when and how to transmit to the given peer.
 *
 * @param cls the `struct PeerPlan`
 */
static void
schedule_peer_transmission (void *cls)
{
  struct PeerPlan *pp = cls;
  struct GSF_RequestPlan *rp;
  struct GNUNET_TIME_Relative delay;

  if (NULL != pp->task)
  {
    pp->task = NULL;
  }
  else
  {
    GNUNET_assert (NULL != pp->env);
    pp->env = NULL;
  }
  /* move ready requests to priority queue */
  while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) &&
         (0 == GNUNET_TIME_absolute_get_remaining
          (rp->earliest_transmission).rel_value_us))
  {
    GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap));
    rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap,
                                           rp,
                                           rp->priority);
  }
  if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap))
  {
    /* priority heap (still) empty, check for delay... */
    rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap);
    if (NULL == rp)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "No active requests for plan %p.\n",
                  pp);
      return;                   /* both queues empty */
    }
    delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Sleeping for %s before retrying requests on plan %p.\n",
                GNUNET_STRINGS_relative_time_to_string (delay,
							GNUNET_YES),
		pp);
    GNUNET_STATISTICS_set (GSF_stats,
                           gettext_noop ("# delay heap timeout (ms)"),
                           delay.rel_value_us / 1000LL, GNUNET_NO);

    pp->task =
        GNUNET_SCHEDULER_add_delayed (delay,
                                      &schedule_peer_transmission,
                                      pp);
    return;
  }
#if INSANE_STATISTICS
  GNUNET_STATISTICS_update (GSF_stats,
			    gettext_noop ("# query plans executed"),
                            1,
			    GNUNET_NO);
#endif
  /* process from priority heap */
  rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Executing query plan %p\n",
              rp);
  GNUNET_assert (NULL != rp);
  rp->hn = NULL;
  rp->last_transmission = GNUNET_TIME_absolute_get ();
  rp->transmission_counter++;
  total_delay++;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Executing plan %p executed %u times, planning retransmission\n",
              rp,
	      rp->transmission_counter);
  GNUNET_assert (NULL == pp->env);
  pp->env = GSF_pending_request_get_message_ (get_latest (rp));
  GNUNET_MQ_notify_sent (pp->env,
			 &schedule_peer_transmission,
			 pp);
  GSF_peer_transmit_ (pp->cp,
		      GNUNET_YES,
		      rp->priority,
		      pp->env);
  GNUNET_STATISTICS_update (GSF_stats,
                            gettext_noop ("# query messages sent to other peers"),
                            1,
                            GNUNET_NO);
  plan (pp,
	rp);
}