*/
struct PendingRequestList;
+/**
+ * Transmission plan for a peer.
+ */
+struct PeerPlan;
+
/**
* DLL of request plans a particular pending request is
struct PendingRequestList *prev;
/**
- * Array of associated pending requests.
+ * Associated pending request.
*/
struct GSF_PendingRequest *pr;
*/
struct GNUNET_CONTAINER_HeapNode *hn;
+ /**
+ * The transmission plan for a peer that this request is associated with.
+ */
+ struct PeerPlan *pp;
+
/**
* Head of list of associated pending requests.
*/
*/
struct GNUNET_CONTAINER_Heap *delay_heap;
+ /**
+ * Map of queries to plan entries. All entries in the priority_heap or delay_heap
+ * should be in the plan map. Note that it IS possible for the plan map to have
+ * multiple entries for the same query.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *plan_map;
+
/**
* Current transmission request handle.
*/
static unsigned long long plan_count;
+/**
+ * Return the query (key in the plan_map) for the given request plan.
+ *
+ * @param rp a request plan
+ * @return the associated query
+ */
+static const GNUNET_HashCode *
+get_rp_key (struct GSF_RequestPlan *rp)
+{
+ return &GSF_pending_request_get_data_ (rp->prl_head->pr)->query;
+}
+
+
/**
* Figure out when and how to transmit to the given peer.
*
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);
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);
* present for this peer.
*
* @param cls closure
- * @param node internal node of the heap (ignored)
+ * @param query the query
* @param element request plan stored at the node
- * @param cost cost associated with the node (ignored)
* @return GNUNET_YES if we should continue to iterate,
* GNUNET_NO if not (merge success)
*/
static int
-merge_pr (void *cls, struct GNUNET_CONTAINER_HeapNode *node, void *element,
- GNUNET_CONTAINER_HeapCostType cost)
+merge_pr (void *cls,
+ const GNUNET_HashCode *query,
+ void *element)
{
struct MergeContext *mpr = cls;
struct GSF_RequestPlan *rp = element;
if (NULL == pp)
{
pp = GNUNET_malloc (sizeof (struct PeerPlan));
+ pp->plan_map =
+ GNUNET_CONTAINER_multihashmap_create (128);
pp->priority_heap =
GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
pp->delay_heap =
}
mpc.merged = GNUNET_NO;
mpc.pr = pr;
- /* FIXME: O(n) call here, LRN reports this is a performance
- problem. Try using hash map!? */
- GNUNET_CONTAINER_heap_iterate (pp->priority_heap, &merge_pr, &mpc);
+ GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map,
+ &GSF_pending_request_get_data_ (pr)->query,
+ &merge_pr, &mpc);
if (mpc.merged != GNUNET_NO)
return;
- GNUNET_CONTAINER_heap_iterate (pp->delay_heap, &merge_pr, &mpc);
+ GNUNET_CONTAINER_multihashmap_get_multiple (pp->plan_map,
+ &GSF_pending_request_get_data_ (pr)->query,
+ &merge_pr, &mpc);
if (mpc.merged != GNUNET_NO)
return;
plan_count++;
prl->pr = pr;
GNUNET_CONTAINER_DLL_insert (prd->rpr_head, prd->rpr_tail, rpr);
GNUNET_CONTAINER_DLL_insert (rp->prl_head, rp->prl_tail, prl);
+ rp->pp = pp;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_put (pp->plan_map,
+ get_rp_key (rp),
+ rp,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
plan (pp, rp);
}
}
while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap)))
{
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (pp->plan_map,
+ get_rp_key (rp),
+ rp));
while (NULL != (prl = rp->prl_head))
{
GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, prl);
GNUNET_CONTAINER_heap_destroy (pp->priority_heap);
while (NULL != (rp = GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)))
{
+ GNUNET_CONTAINER_multihashmap_remove (pp->plan_map,
+ get_rp_key (rp),
+ rp);
while (NULL != (prl = rp->prl_head))
{
GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, prl);
plan_count, GNUNET_NO);
GNUNET_CONTAINER_heap_destroy (pp->delay_heap);
+ GNUNET_CONTAINER_multihashmap_destroy (pp->plan_map);
GNUNET_free (pp);
}
GNUNET_CONTAINER_DLL_remove (prd->rpr_head, prd->rpr_tail, rpr);
rp = rpr->rp;
GNUNET_CONTAINER_DLL_remove (rp->prl_head, rp->prl_tail, rpr->prl);
- GNUNET_free (rpr->prl);
- GNUNET_free (rpr);
- if (rp->prl_head == 0)
+ if (NULL == rp->prl_head)
{
GNUNET_CONTAINER_heap_remove_node (rp->hn);
plan_count--;
+ GNUNET_CONTAINER_multihashmap_remove (rp->pp->plan_map,
+ &GSF_pending_request_get_data_ (rpr->prl->pr)->query,
+ rp);
GNUNET_free (rp);
}
+ GNUNET_free (rpr->prl);
+ GNUNET_free (rpr);
}
GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# query plan entries"),
plan_count, GNUNET_NO);