/**
 * Task that looks at the 'retry_heap' and transmits all of the requests
 * on the heap that are ready for transmission.  Then re-schedules
 * itself (unless the heap is empty).
 *
 * @param cls unused
 * @param tc scheduler context
 */
static void
transmit_next_request_task (void *cls,
                            const struct GNUNET_SCHEDULER_TaskContext *tc)
{
  struct ClientQueryRecord *cqr;
  struct GNUNET_TIME_Relative delay;

  retry_task = GNUNET_SCHEDULER_NO_TASK;
  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
    return;
  while (NULL != (cqr = GNUNET_CONTAINER_heap_remove_root (retry_heap)))
  {
    cqr->hnode = NULL;
    delay = GNUNET_TIME_absolute_get_remaining (cqr->retry_time);
    if (delay.rel_value_us > 0)
    {
      cqr->hnode =
          GNUNET_CONTAINER_heap_insert (retry_heap, cqr,
                                        cqr->retry_time.abs_value_us);
      retry_task =
          GNUNET_SCHEDULER_add_delayed (delay, &transmit_next_request_task,
                                        NULL);
      return;
    }
    transmit_request (cqr);
    cqr->hnode =
        GNUNET_CONTAINER_heap_insert (retry_heap, cqr,
                                      cqr->retry_time.abs_value_us);
  }
}
Ejemplo n.º 2
0
/**
 * Store an item in the datastore.
 *
 * @param cls closure
 * @param key key for the item
 * @param size number of bytes in data
 * @param data content stored
 * @param type type of the content
 * @param priority priority of the content
 * @param anonymity anonymity-level for the content
 * @param replication replication-level for the content
 * @param expiration expiration time for the content
 * @param msg set to error message
 * @return GNUNET_OK on success
 */
static int
heap_plugin_put (void *cls, 
		 const struct GNUNET_HashCode * key, 
		 uint32_t size,
		 const void *data, 
		 enum GNUNET_BLOCK_Type type,
		 uint32_t priority, uint32_t anonymity,
		 uint32_t replication,
		 struct GNUNET_TIME_Absolute expiration, char **msg)
{
  struct Plugin *plugin = cls;
  struct Value *value;

  value = GNUNET_malloc (sizeof (struct Value) + size);
  value->key = *key;
  value->data = &value[1];
  value->expire_heap = GNUNET_CONTAINER_heap_insert (plugin->by_expiration,
						     value,
						     expiration.abs_value);
  value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication,
							  value,
							  replication);
  value->expiration = expiration;
  if (0 == anonymity)
  {
    struct ZeroAnonByType *zabt;

    for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
      if (zabt->type == type)
	break;
    if (NULL == zabt)
    {
      zabt = GNUNET_malloc (sizeof (struct ZeroAnonByType));
      zabt->type = type;
      GNUNET_CONTAINER_DLL_insert (plugin->zero_head,
				   plugin->zero_tail,
				   zabt);
    }
    if (zabt->array_size == zabt->array_pos)
    {
      GNUNET_array_grow (zabt->array,
			 zabt->array_size,
			 zabt->array_size * 2 + 4);
    }
    value->zero_anon_offset = zabt->array_pos;
    zabt->array[zabt->array_pos++] = value;
  }
  value->size = size;
  value->priority = priority;
  value->anonymity = anonymity;
  value->replication = replication;
  value->type = type;
  memcpy (&value[1], data, size);
  GNUNET_CONTAINER_multihashmap_put (plugin->keyvalue,
				     &value->key,
				     value,
				     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  plugin->size += size;
  return GNUNET_OK;
}
Ejemplo n.º 3
0
/**
 * 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);
}
Ejemplo n.º 4
0
/**
 * Get a random item for replication.  Returns a single, not expired,
 * random item from those with the highest replication counters.  The
 * item's replication counter is decremented by one IF it was positive
 * before.  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_replication (void *cls, 
			     PluginDatumProcessor proc,
			     void *proc_cls)
{
  struct Plugin *plugin = cls;
  struct Value *value;

  value = GNUNET_CONTAINER_heap_remove_root (plugin->by_replication);
  if (NULL == value)
  {
    proc (proc_cls, 
	  NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
    return;
  }
  if (value->replication > 0)
  {
    value->replication--;
    value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication,
							    value,
							    value->replication); 
  }
  else
  {
    /* need a better way to pick a random item, replication level is always 0 */
    value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication,
							    value,
							    value->replication); 
    value = GNUNET_CONTAINER_heap_walk_get_next (plugin->by_replication);
  }
  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);
}
/**
 * Add a new entry to our routing table.
 *
 * @param sender peer that originated the request
 * @param type type of the block
 * @param options options for processing
 * @param key key for the content
 * @param xquery extended query
 * @param xquery_size number of bytes in xquery
 * @param reply_bf bloomfilter to filter duplicates
 * @param reply_bf_mutator mutator for reply_bf
*/
void
GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
                 enum GNUNET_BLOCK_Type type,
                 enum GNUNET_DHT_RouteOption options,
                 const struct GNUNET_HashCode * key, const void *xquery,
                 size_t xquery_size,
                 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
                 uint32_t reply_bf_mutator)
{
  struct RecentRequest *recent_req;

  while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT)
    expire_oldest_entry ();
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop ("# Entries added to routing table"),
                            1, GNUNET_NO);
  recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size);
  recent_req->peer = *sender;
  recent_req->key = *key;
  recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf);
  recent_req->type = type;
  recent_req->options = options;
  recent_req->xquery = &recent_req[1];
  memcpy (&recent_req[1], xquery, xquery_size);
  recent_req->xquery_size = xquery_size;
  recent_req->reply_bf_mutator = reply_bf_mutator;
  if (GNUNET_SYSERR ==
      GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key,
						  &try_combine_recent, recent_req))
  {
    GNUNET_STATISTICS_update (GDS_stats,
                              gettext_noop
                              ("# DHT requests combined"),
                              1, GNUNET_NO);
    return;
  }
  recent_req->heap_node =
      GNUNET_CONTAINER_heap_insert (recent_heap, recent_req,
                                    GNUNET_TIME_absolute_get ().abs_value);
  GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);


}
/**
 * Handler for DHT GET messages from the client.
 *
 * @param cls closure for the service
 * @param client the client we received this message from
 * @param message the actual message received
 */
static void
handle_dht_local_get (void *cls, struct GNUNET_SERVER_Client *client,
                      const struct GNUNET_MessageHeader *message)
{
  const struct GNUNET_DHT_ClientGetMessage *get;
  struct ClientQueryRecord *cqr;
  size_t xquery_size;
  const char *xquery;
  uint16_t size;

  size = ntohs (message->size);
  if (size < sizeof (struct GNUNET_DHT_ClientGetMessage))
  {
    GNUNET_break (0);
    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
    return;
  }
  xquery_size = size - sizeof (struct GNUNET_DHT_ClientGetMessage);
  get = (const struct GNUNET_DHT_ClientGetMessage *) message;
  xquery = (const char *) &get[1];
  GNUNET_STATISTICS_update (GDS_stats,
                            gettext_noop
                            ("# GET requests received from clients"), 1,
                            GNUNET_NO);
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received GET request for %s from local client %p, xq: %.*s\n",
       GNUNET_h2s (&get->key), client, xquery_size, xquery);

  LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "XDHT CLIENT-GET %s @ %u\n",
               GNUNET_h2s (&get->key), getpid ());


  cqr = GNUNET_malloc (sizeof (struct ClientQueryRecord) + xquery_size);
  cqr->key = get->key;
  cqr->client = find_active_client (client);
  cqr->xquery = (void *) &cqr[1];
  memcpy (&cqr[1], xquery, xquery_size);
  cqr->hnode = GNUNET_CONTAINER_heap_insert (retry_heap, cqr, 0);
  cqr->retry_frequency = GNUNET_TIME_UNIT_SECONDS;
  cqr->retry_time = GNUNET_TIME_absolute_get ();
  cqr->unique_id = get->unique_id;
  cqr->xquery_size = xquery_size;
  cqr->replication = ntohl (get->desired_replication_level);
  cqr->msg_options = ntohl (get->options);
  cqr->type = ntohl (get->type);
  // FIXME use cqr->key, set multihashmap create to GNUNET_YES
  GNUNET_CONTAINER_multihashmap_put (forward_map, &get->key, cqr,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  GDS_CLIENTS_process_get (ntohl (get->options),
                           ntohl (get->type),
                           0,
                           ntohl (get->desired_replication_level),
                           1,
                           GDS_NEIGHBOURS_get_id(),
                           &get->key);
  /* start remote requests */
  if (GNUNET_SCHEDULER_NO_TASK != retry_task)
    GNUNET_SCHEDULER_cancel (retry_task);
  retry_task = GNUNET_SCHEDULER_add_now (&transmit_next_request_task, NULL);
  /* perform local lookup */
  GDS_DATACACHE_handle_get (&get->key, cqr->type, cqr->xquery, xquery_size,
                            NULL, 0);
  GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
/**
 * Insert the given request plan into the heap with the appropriate weight.
 *
 * @param pp associated peer's plan
 * @param rp request to plan
 */
static void
plan (struct PeerPlan *pp, struct GSF_RequestPlan *rp)
{
#define N ((double)128.0)
  /**
   * Running average delay we currently impose.
   */
  static double avg_delay;

  struct GSF_PendingRequestData *prd;
  struct GNUNET_TIME_Relative delay;

  GNUNET_assert (rp->pp == pp);
  GNUNET_STATISTICS_set (GSF_stats,
                         gettext_noop ("# average retransmission delay (ms)"),
                         total_delay * 1000LL / plan_count, GNUNET_NO);
  prd = GSF_pending_request_get_data_ (rp->pe_head->pr);

  if (rp->transmission_counter < 8)
    delay =
        GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
                                       rp->transmission_counter);
  else if (rp->transmission_counter < 32)
    delay =
        GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
                                       8 +
                                       (1LL << (rp->transmission_counter - 8)));
  else
    delay =
        GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
                                       8 + (1LL << 24));
  delay.rel_value =
      GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
                                delay.rel_value + 1);
  /* Add 0.01 to avg_delay to avoid division-by-zero later */
  avg_delay = (((avg_delay * (N - 1.0)) + delay.rel_value) / N) + 0.01;

  /*
   * For the priority, we need to consider a few basic rules:
   * 1) if we just started requesting (delay is small), we should
   * virtually always have a priority of zero.
   * 2) for requests with average latency, our priority should match
   * the average priority observed on the network
   * 3) even the longest-running requests should not be WAY out of
   * the observed average (thus we bound by a factor of 2)
   * 4) we add +1 to the observed average priority to avoid everyone
   * staying put at zero (2 * 0 = 0...).
   *
   * Using the specific calculation below, we get:
   *
   * delay = 0 => priority = 0;
   * delay = avg delay => priority = running-average-observed-priority;
   * delay >> avg_delay => priority = 2 * running-average-observed-priority;
   *
   * which satisfies all of the rules above.
   *
   * Note: M_PI_4 = PI/4 = arctan(1)
   */
  rp->priority =
      round ((GSF_current_priorities +
              1.0) * atan (delay.rel_value / avg_delay)) / M_PI_4;
  /* Note: usage of 'round' and 'atan' requires -lm */

  if (rp->transmission_counter != 0)
    delay.rel_value += TTL_DECREMENT;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Considering (re)transmission number %u in %llu ms\n",
              (unsigned int) rp->transmission_counter,
              (unsigned long long) delay.rel_value);
  rp->earliest_transmission = GNUNET_TIME_relative_to_absolute (delay);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Earliest (re)transmission for `%s' in %us\n",
              GNUNET_h2s (&prd->query), rp->transmission_counter);
  GNUNET_assert (rp->hn == NULL);
  if (GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value
      == 0)
    rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority);
  else
    rp->hn =
        GNUNET_CONTAINER_heap_insert (pp->delay_heap, rp,
                                      rp->earliest_transmission.abs_value);
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_contains_value (pp->plan_map,
                                                               get_rp_key (rp),
                                                               rp));
  if (GNUNET_SCHEDULER_NO_TASK != pp->task)
    GNUNET_SCHEDULER_cancel (pp->task);
  pp->task = GNUNET_SCHEDULER_add_now (&schedule_peer_transmission, pp);
#undef N
}
Ejemplo n.º 9
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);
}