int main(void) { message_queue *q = mq_create(); message_node *n = NULL; printf("size should be 0, is %d\n", mq_size(q)); mq_push_msgz(q, "one"); mq_push_msgz(q, "two"); mq_push_msgz(q, "three"); printf("size should be 3, is %d\n", mq_size(q)); n = mq_pop(q); printf("expecting \"one\", got \"%s\"\n", n->message); mn_destroy(n); mq_push_msgz(q, "four"); n = mq_pop(q); printf("expecting \"two\", got \"%s\"\n", n->message); mn_destroy(n); n = mq_pop(q); printf("expecting \"three\", got \"%s\"\n", n->message); mn_destroy(n); printf("size should be 1, is %d\n", mq_size(q)); n = mq_pop(q); printf("expecting \"four\", got \"%s\"\n", n->message); mn_destroy(n); printf("size should be 0, is %d\n", mq_size(q)); n = mq_pop(q); printf("expecting \"%p\", got \"%p\"\n", NULL, n); mq_destroy(q); return 0; }
/** * Based on the information we have on the query hits we already * seen or enqueued, determine whether we're going to drop this * message on the floor or forward it. */ static enum dh_drop dh_can_forward(dqhit_t *dh, mqueue_t *mq, bool test) { const char *teststr = test ? "[test] " : ""; g_assert(mq != NULL); /* * The heart of the "dynamic hit routing" algorithm is here. */ /* * If the queue already has more bytes queued than its high-watermark, * meaning it is in the dangerous zone, drop this hit if we sent more * than DH_THRESH_HITS already or have enough in the queue to reach the * DH_MIN_HITS level. */ if ( mq_size(mq) > mq_hiwat(mq) && /* Implies we're flow-controlled */ (dh->hits_sent >= DH_THRESH_HITS || dh->hits_queued >= DH_MIN_HITS) ) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %squeue size > hiwat, dropping", teststr); return DH_DROP_FC; } /* * In SWIFT mode, we're aggressively dropping messages from the queue. * We're in flow control, but we're probably lower than hiwat, the * heaviest condition. Be more tolerant before dropping, meaning * a strongest dropping rule than the above. */ if ( mq_is_swift_controlled(mq) && (dh->hits_sent >= DH_MIN_HITS || dh->hits_queued >= DH_MIN_HITS) ) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %squeue in SWIFT mode, dropping", teststr); return DH_DROP_FC; } /* * Queue is flow-controlled, don't add to its burden if we * already have hits enqueued for this query with results sent. */ if ( mq_is_flow_controlled(mq) && ( (dh->hits_sent >= DH_MIN_HITS && dh->hits_queued >= 2 * DH_THRESH_HITS) || (dh->hits_sent < DH_MIN_HITS && (dh->hits_sent + dh->hits_queued) >= DH_MIN_HITS + DH_THRESH_HITS) ) ) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %squeue in FLOWC mode, dropping", teststr); return DH_DROP_FC; } /* * If the queue has more bytes than its low-watermark, meaning * it is in the warning zone, drop if we sent more then DH_POPULAR_HITS * already, and we have quite a few queued. */ if ( mq_size(mq) > mq_lowat(mq) && dh->hits_sent >= DH_POPULAR_HITS && dh->hits_queued >= (DH_MIN_HITS / 2) ) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %squeue size > lowat, dropping", teststr); return DH_DROP_FC; } /* * If we sent more than DH_POPULAR_HITS and have DH_MIN_HITS queued, * don't add more and throttle. */ if ( dh->hits_sent >= DH_POPULAR_HITS && dh->hits_queued >= DH_MIN_HITS ) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %senough hits queued, throttling", teststr); return DH_DROP_THROTTLE; } /* * If what we sent plus what we hold will top the maximum number of hits, * yet we did not reach the maximum, drop: we need to leave room for * other hits for less popular results. */ if ( dh->hits_sent < DH_MAX_HITS && dh->hits_queued > (DH_MIN_HITS / 2) && (dh->hits_queued + dh->hits_sent) >= DH_MAX_HITS) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %senough queued, nearing max, throttling", teststr); return DH_DROP_THROTTLE; } /* * Finally, if what we have sent makes up for more than DH_MAX_HITS and * we have anything queued for that query, drop. */ if (dh->hits_sent >= DH_MAX_HITS && dh->hits_queued) { if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %smax sendable hits reached, throttling", teststr); return DH_DROP_THROTTLE; } /* * Transient nodes are going to go away soon, results should not be * forwarded to them since they may not be relayed in time anyway or * could be just a waste of bandwidth. * * Avoid them if they already have enough in their TX queue. */ { gnutella_node_t *n = mq_node(mq); if (NODE_IS_TRANSIENT(n) && mq_size(mq) > mq_lowat(mq)) { if (GNET_PROPERTY(dh_debug) > 19) { g_debug("DH %stransient target %s with %d bytes in queue", teststr, node_infostr(n), mq_size(mq)); } return DH_DROP_TRANSIENT; } } if (GNET_PROPERTY(dh_debug) > 19) g_debug("DH %sforwarding", teststr); return DH_FORWARD; }