Ejemplo n.º 1
0
void    qmgr_transport_unthrottle(QMGR_TRANSPORT *transport)
{
    const char *myname = "qmgr_transport_unthrottle";

    /*
     * This routine runs after expiration of the timer set by
     * qmgr_transport_throttle(), or whenever a delivery transport has been
     * used without malfunction. In either case, we enable delivery again if
     * the transport was throttled. We always reset the transport rate lock.
     */
    if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) {
	if (msg_verbose)
	    msg_info("%s: transport %s", myname, transport->name);
	transport->flags &= ~QMGR_TRANSPORT_STAT_DEAD;
	if (transport->dsn == 0)
	    msg_panic("%s: transport %s: null reason",
		      myname, transport->name);
	dsn_free(transport->dsn);
	transport->dsn = 0;
	event_cancel_timer(qmgr_transport_unthrottle_wrapper,
			   (void *) transport);
    }
    if (transport->flags & QMGR_TRANSPORT_STAT_RATE_LOCK)
	transport->flags &= ~QMGR_TRANSPORT_STAT_RATE_LOCK;
}
Ejemplo n.º 2
0
static void deliver_request_free(DELIVER_REQUEST *request)
{
    if (request->fp)
	vstream_fclose(request->fp);
    if (request->queue_name)
	myfree(request->queue_name);
    if (request->queue_id)
	myfree(request->queue_id);
    if (request->nexthop)
	myfree(request->nexthop);
    if (request->encoding)
	myfree(request->encoding);
    if (request->sender)
	myfree(request->sender);
    recipient_list_free(&request->rcpt_list);
    if (request->hop_status)
	dsn_free(request->hop_status);
    if (request->client_name)
	myfree(request->client_name);
    if (request->client_addr)
	myfree(request->client_addr);
    if (request->client_port)
	myfree(request->client_port);
    if (request->client_proto)
	myfree(request->client_proto);
    if (request->client_helo)
	myfree(request->client_helo);
    if (request->sasl_method)
	myfree(request->sasl_method);
    if (request->sasl_username)
	myfree(request->sasl_username);
    if (request->sasl_sender)
	myfree(request->sasl_sender);
    if (request->rewrite_context)
	myfree(request->rewrite_context);
    if (request->dsn_envid)
	myfree(request->dsn_envid);
    myfree((char *) request);
}
Ejemplo n.º 3
0
void    qmgr_queue_unthrottle(QMGR_QUEUE *queue)
{
    const char *myname = "qmgr_queue_unthrottle";
    QMGR_TRANSPORT *transport = queue->transport;
    double  feedback;

    if (msg_verbose)
	msg_info("%s: queue %s", myname, queue->name);

    /*
     * Sanity checks.
     */
    if (!QMGR_QUEUE_READY(queue) && !QMGR_QUEUE_THROTTLED(queue))
	msg_panic("%s: bad queue status: %s", myname, QMGR_QUEUE_STATUS(queue));

    /*
     * Don't restart the negative feedback hysteresis cycle with every
     * positive feedback. Restart it only when we make a positive concurrency
     * adjustment (i.e. at the end of a positive feedback hysteresis cycle).
     * Otherwise negative feedback would be too aggressive: negative feedback
     * takes effect immediately at the start of its hysteresis cycle.
     */
    queue->fail_cohorts = 0;

    /*
     * Special case when this site was dead.
     */
    if (QMGR_QUEUE_THROTTLED(queue)) {
	event_cancel_timer(qmgr_queue_unthrottle_wrapper, (char *) queue);
	if (queue->dsn == 0)
	    msg_panic("%s: queue %s: window 0 status 0", myname, queue->name);
	dsn_free(queue->dsn);
	queue->dsn = 0;
	/* Back from the almost grave, best concurrency is anyone's guess. */
	if (queue->busy_refcount > 0)
	    queue->window = queue->busy_refcount;
	else
	    queue->window = transport->init_dest_concurrency;
	queue->success = queue->failure = 0;
	QMGR_LOG_WINDOW(queue);
	return;
    }

    /*
     * Increase the destination's concurrency limit until we reach the
     * transport's concurrency limit. Allow for a margin the size of the
     * initial destination concurrency, so that we're not too gentle.
     * 
     * Why is the concurrency increment based on preferred concurrency and not
     * on the number of outstanding delivery requests? The latter fluctuates
     * wildly when deliveries complete in bursts (artificial benchmark
     * measurements), and does not account for cached connections.
     * 
     * Keep the window within reasonable distance from actual concurrency
     * otherwise negative feedback will be ineffective. This expression
     * assumes that busy_refcount changes gradually. This is invalid when
     * deliveries complete in bursts (artificial benchmark measurements).
     */
    if (transport->dest_concurrency_limit == 0
	|| transport->dest_concurrency_limit > queue->window)
	if (queue->window < queue->busy_refcount + transport->init_dest_concurrency) {
	    feedback = QMGR_FEEDBACK_VAL(transport->pos_feedback, queue->window);
	    QMGR_LOG_FEEDBACK(feedback);
	    queue->success += feedback;
	    /* Prepare for overshoot (feedback > hysteresis, rounding error). */
	    while (queue->success + feedback / 2 >= transport->pos_feedback.hysteresis) {
		queue->window += transport->pos_feedback.hysteresis;
		queue->success -= transport->pos_feedback.hysteresis;
		queue->failure = 0;
	    }
	    /* Prepare for overshoot. */
	    if (transport->dest_concurrency_limit > 0
		&& queue->window > transport->dest_concurrency_limit)
		queue->window = transport->dest_concurrency_limit;
	}
    QMGR_LOG_WINDOW(queue);
}