コード例 #1
0
/**
 * Notify the plan about a request being done; destroy all entries
 * associated with this request.
 *
 * @param pr request that is done
 */
void
GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr)
{
  struct GSF_RequestPlan *rp;
  struct GSF_PendingRequestData *prd;
  struct GSF_PendingRequestPlanBijection *bi;

  prd = GSF_pending_request_get_data_ (pr);
  while (NULL != (bi = prd->pr_head))
  {
    rp = bi->rp;
    GNUNET_CONTAINER_MDLL_remove (PR, prd->pr_head, prd->pr_tail, bi);
    GNUNET_CONTAINER_MDLL_remove (PE, rp->pe_head, rp->pe_tail, bi);
    if (NULL == rp->pe_head)
    {
      GNUNET_CONTAINER_heap_remove_node (rp->hn);
      plan_count--;
      GNUNET_break (GNUNET_YES ==
                    GNUNET_CONTAINER_multihashmap_remove (rp->pp->plan_map,
							  &GSF_pending_request_get_data_
							  (bi->pr)->query,
                                                          rp));
      GNUNET_free (rp);
    }
    GNUNET_free (bi);
  }
  GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"),
                         plan_count, GNUNET_NO);
}
コード例 #2
0
ファイル: gnunet-service-fs_pe.c プロジェクト: GNUnet/gnunet
/**
 * Get the pending request with the highest TTL from the given plan.
 *
 * @param rp plan to investigate
 * @return pending request with highest TTL
 */
struct GSF_PendingRequest *
get_latest (const struct GSF_RequestPlan *rp)
{
  struct GSF_PendingRequest *ret;
  struct GSF_PendingRequestPlanBijection *bi;
  const struct GSF_PendingRequestData *rprd;
  const struct GSF_PendingRequestData *prd;

  bi = rp->pe_head;
  if (NULL == bi)
    return NULL; /* should never happen */
  ret = bi->pr;
  rprd = GSF_pending_request_get_data_ (ret);
  for (bi = bi->next_PE; NULL != bi; bi = bi->next_PE)
  {
    GNUNET_break (GNUNET_YES ==
                  GSF_pending_request_test_active_ (bi->pr));
    prd = GSF_pending_request_get_data_ (bi->pr);
    if (prd->ttl.abs_value_us > rprd->ttl.abs_value_us)
    {
      ret = bi->pr;
      rprd = prd;
    }
  }
  return ret;
}
コード例 #3
0
/**
 * Create a new query plan entry.
 *
 * @param cp peer with the entry
 * @param pr request with the entry
 */
void
GSF_plan_add_ (struct GSF_ConnectedPeer *cp, struct GSF_PendingRequest *pr)
{
  const struct GNUNET_PeerIdentity *id;
  struct PeerPlan *pp;
  struct GSF_PendingRequestData *prd;
  struct GSF_RequestPlan *rp;
  struct GSF_PendingRequestPlanBijection *bi;
  struct MergeContext mpc;

  GNUNET_assert (NULL != cp);
  id = GSF_connected_peer_get_identity2_ (cp);
  pp = GNUNET_CONTAINER_multihashmap_get (plans, &id->hashPubKey);
  if (NULL == pp)
  {
    pp = GNUNET_malloc (sizeof (struct PeerPlan));
    pp->plan_map = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
    pp->priority_heap =
        GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
    pp->delay_heap =
        GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
    pp->cp = cp;
    GNUNET_CONTAINER_multihashmap_put (plans, 
				       &id->hashPubKey, pp,
                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
  }
  mpc.merged = GNUNET_NO;
  mpc.pr = pr;
  GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map,
                                              &GSF_pending_request_get_data_
                                              (pr)->query, &merge_pr, &mpc); // 8 MB in 'merge_pr'
  if (GNUNET_NO != mpc.merged)
    return;
  GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map,
                                              &GSF_pending_request_get_data_
                                              (pr)->query, &merge_pr, &mpc);
  if (GNUNET_NO != mpc.merged)
    return;
  plan_count++;
  GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plan entries"), 1,
                            GNUNET_NO);
  prd = GSF_pending_request_get_data_ (pr);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Planning transmission of query `%s' to peer `%s'\n",
              GNUNET_h2s (&prd->query), GNUNET_i2s (id));
  rp = GNUNET_malloc (sizeof (struct GSF_RequestPlan)); // 8 MB
  bi = GNUNET_malloc (sizeof (struct GSF_PendingRequestPlanBijection));
  bi->rp = rp;
  bi->pr = pr;
  GNUNET_CONTAINER_MDLL_insert (PR, prd->pr_head, prd->pr_tail, bi);
  GNUNET_CONTAINER_MDLL_insert (PE, rp->pe_head, rp->pe_tail, bi);
  rp->pp = pp;
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_put (pp->plan_map,
                                                    get_rp_key (rp), rp,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); // 8 MB
  plan (pp, rp); // +5 MB (plan/heap-insert)
}
コード例 #4
0
/**
 * Get the pending request with the highest TTL from the given plan.
 *
 * @param rp plan to investigate
 * @return pending request with highest TTL
 */
struct GSF_PendingRequest *
get_latest (const struct GSF_RequestPlan *rp)
{
  struct GSF_PendingRequest *ret;
  struct GSF_PendingRequestPlanBijection *bi;

  bi = rp->pe_head;
  if (NULL == bi)
    return NULL; /* should never happen */
  ret = bi->pr;
  bi = bi->next_PE; 
  while (NULL != bi)
  {
    if (GSF_pending_request_get_data_ (bi->pr)->ttl.abs_value >
        GSF_pending_request_get_data_ (ret)->ttl.abs_value)
      ret = bi->pr;
    bi = bi->next_PE;
  }
  return ret;
}
コード例 #5
0
/**
 * Iterator that checks if an equivalent request is already
 * present for this peer.
 *
 * @param cls closure
 * @param query the query
 * @param element request plan stored at the node
 * @return GNUNET_YES if we should continue to iterate,
 *         GNUNET_NO if not (merge success)
 */
static int
merge_pr (void *cls, const struct GNUNET_HashCode * query, void *element)
{
  struct MergeContext *mpr = cls;
  struct GSF_RequestPlan *rp = element;
  struct GSF_PendingRequestData *prd;
  struct GSF_PendingRequestPlanBijection *bi;
  struct GSF_PendingRequest *latest;

  if (GNUNET_OK !=
      GSF_pending_request_is_compatible_ (mpr->pr, rp->pe_head->pr))
    return GNUNET_YES;
  /* merge new request with existing request plan */
  bi = GNUNET_malloc (sizeof (struct GSF_PendingRequestPlanBijection));
  bi->rp = rp;
  bi->pr = mpr->pr;
  prd = GSF_pending_request_get_data_ (mpr->pr);
  GNUNET_CONTAINER_MDLL_insert (PR, prd->pr_head, prd->pr_tail, bi);
  GNUNET_CONTAINER_MDLL_insert (PE, rp->pe_head, rp->pe_tail, bi);
  mpr->merged = GNUNET_YES;
#if INSANE_STATISTICS
  GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests merged"), 1,
                            GNUNET_NO);
#endif
  latest = get_latest (rp);
  if (GSF_pending_request_get_data_ (latest)->ttl.abs_value <
      prd->ttl.abs_value)
  {
#if INSANE_STATISTICS
    GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# requests refreshed"),
                              1, GNUNET_NO);
#endif
    rp->transmission_counter = 0;       /* reset */
  }
  return GNUNET_NO;
}
コード例 #6
0
/**
 * Notify the plan about a peer being no longer available;
 * destroy all entries associated with this peer.
 *
 * @param cp connected peer
 */
void
GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp)
{
  const struct GNUNET_PeerIdentity *id;
  struct PeerPlan *pp;
  struct GSF_RequestPlan *rp;
  struct GSF_PendingRequestData *prd;
  struct GSF_PendingRequestPlanBijection *bi;

  id = GSF_connected_peer_get_identity2_ (cp);
  pp = GNUNET_CONTAINER_multihashmap_get (plans, &id->hashPubKey);
  if (NULL == pp)
    return;                     /* nothing was ever planned for this peer */
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CONTAINER_multihashmap_remove (plans, &id->hashPubKey,
                                                       pp));
  if (NULL != pp->pth)
  {
    GSF_peer_transmit_cancel_ (pp->pth);
    pp->pth = NULL;
  }
  if (GNUNET_SCHEDULER_NO_TASK != pp->task)
  {
    GNUNET_SCHEDULER_cancel (pp->task);
    pp->task = GNUNET_SCHEDULER_NO_TASK;
  }
  while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap)))
  {
    GNUNET_break (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap_remove (pp->plan_map,
                                                        get_rp_key (rp), rp));
    while (NULL != (bi = rp->pe_head))
    {
      GNUNET_CONTAINER_MDLL_remove (PE, rp->pe_head, rp->pe_tail, bi);
      prd = GSF_pending_request_get_data_ (bi->pr);
      GNUNET_CONTAINER_MDLL_remove (PR, prd->pr_head, prd->pr_tail, bi);
      GNUNET_free (bi);
    }
    plan_count--;
    GNUNET_free (rp);
  }
  GNUNET_CONTAINER_heap_destroy (pp->priority_heap);
  while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)))
  {
    GNUNET_break (GNUNET_YES ==
                  GNUNET_CONTAINER_multihashmap_remove (pp->plan_map,
                                                        get_rp_key (rp), rp));
    while (NULL != (bi = rp->pe_head))
    {
      prd = GSF_pending_request_get_data_ (bi->pr);
      GNUNET_CONTAINER_MDLL_remove (PE, rp->pe_head, rp->pe_tail, bi);
      GNUNET_CONTAINER_MDLL_remove (PR, prd->pr_head, prd->pr_tail, bi);
      GNUNET_free (bi);
    }
    plan_count--;
    GNUNET_free (rp);
  }
  GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"),
                         plan_count, GNUNET_NO);
  GNUNET_CONTAINER_heap_destroy (pp->delay_heap);
  GNUNET_CONTAINER_multihashmap_destroy (pp->plan_map);
  GNUNET_free (pp);
}
コード例 #7
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
}
コード例 #8
0
/**
 * Return the query (key in the plan_map) for the given request plan.
 * Note that this key may change as there can be multiple pending
 * requests for the same key and we just return _one_ of them; this
 * particular one might complete while another one might still be
 * active, hence the lifetime of the returned hash code is NOT
 * necessarily identical to that of the 'struct GSF_RequestPlan'
 * given.
 *
 * @param rp a request plan
 * @return the associated query
 */
static const struct GNUNET_HashCode *
get_rp_key (struct GSF_RequestPlan *rp)
{
  return &GSF_pending_request_get_data_ (rp->pe_head->pr)->query;
}