* where we actually need it (i.e. not if we have a direct connection,
* or if we already have plenty of good short ones, or maybe even
* to take a break if we have some connections and have searched a lot (?))
- * - optimize MQM ready scans (O(n) -> O(1))
*/
#include "platform.h"
#include "gnunet_util_lib.h"
*/
struct GCP_MessageQueueManager *mqm_tail;
+ /**
+ * Pointer to first "ready" entry in @e mqm_head.
+ */
+ struct GCP_MessageQueueManager *mqm_ready_ptr;
+
/**
* MIN-heap of paths owned by this peer (they also end at this
* peer). Ordered by desirability.
notifications. Thus we can assert that mqm_head is empty at this
point. */
GNUNET_assert (NULL == cp->mqm_head);
+ GNUNET_assert (NULL == cp->mqm_ready_ptr);
GNUNET_free (cp);
}
{
struct CadetPeer *cp = mqm->cp;
+ /* Move ready pointer to the next entry that might be ready. */
+ if ( (mqm == cp->mqm_ready_ptr) &&
+ (NULL != mqm->next) )
+ cp->mqm_ready_ptr = mqm->next;
/* Move entry to the end of the DLL, to be fair. */
if (mqm != cp->mqm_tail)
{
}
+/**
+ * Find the next ready message in the queue (starting
+ * the search from the `cp->mqm_ready_ptr`) and if possible
+ * execute the transmission.
+ *
+ * @param cp peer to try to send the next ready message to
+ */
+static void
+send_next_ready (struct CadetPeer *cp)
+{
+ struct GCP_MessageQueueManager *mqm;
+
+ if (0 == cp->mqm_ready_counter)
+ return;
+ while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
+ (NULL == mqm->env) )
+ cp->mqm_ready_ptr = mqm->next;
+ if (NULL == mqm)
+ return; /* nothing to do */
+ mqm_execute (mqm);
+}
+
+
/**
* Function called when CORE took one of the messages from
* a message queue manager and transmitted it.
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Sending to peer %s completed\n",
GCP_2s (cp));
- if (0 == cp->mqm_ready_counter)
- return; /* nothing to do */
- for (struct GCP_MessageQueueManager *mqm = cp->mqm_head;
- NULL != mqm;
- mqm = mqm->next)
- {
- if (NULL == mqm->env)
- continue;
- mqm_execute (mqm);
- return;
- }
+ send_next_ready (cp);
}
{
struct CadetPeer *cp = mqm->cp;
+ GNUNET_assert (NULL != env);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Queueing message to peer %s in MQM %p\n",
GCP_2s (cp),
cp);
mqm->env = env;
cp->mqm_ready_counter++;
+ if (mqm != cp->mqm_ready_ptr)
+ cp->mqm_ready_ptr = cp->mqm_head;
+ if (1 == cp->mqm_ready_counter)
+ cp->mqm_ready_ptr = mqm;
if (0 != GNUNET_MQ_get_length (cp->core_mq))
return;
- mqm_execute (mqm);
+ send_next_ready (cp);
}
else
GNUNET_MQ_discard (last_env);
}
+ if (cp->mqm_ready_ptr == mqm)
+ cp->mqm_ready_ptr = mqm->next;
GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
cp->mqm_tail,
mqm);