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; }
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); }
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); }