5
/* per-site queue entries
9
/* QMGR_ENTRY *qmgr_entry_create(queue, message)
11
/* QMGR_MESSAGE *message;
13
/* void qmgr_entry_done(entry, which)
17
/* QMGR_ENTRY *qmgr_entry_select(queue)
20
/* void qmgr_entry_unselect(queue, entry)
24
/* These routines add/delete/manipulate per-site message
27
/* qmgr_entry_create() creates an entry for the named queue and
28
/* message, and appends the entry to the queue's todo list.
29
/* Filling in and cleaning up the recipients is the responsibility
32
/* qmgr_entry_done() discards a per-site queue entry. The
33
/* \fIwhich\fR argument is either QMGR_QUEUE_BUSY for an entry
34
/* of the site's `busy' list (i.e. queue entries that have been
35
/* selected for actual delivery), or QMGR_QUEUE_TODO for an entry
36
/* of the site's `todo' list (i.e. queue entries awaiting selection
37
/* for actual delivery).
39
/* qmgr_entry_done() triggers cleanup of the per-site queue when
40
/* the site has no pending deliveries, and the site is either
41
/* alive, or the site is dead and the number of in-core queues
42
/* exceeds a configurable limit (see qmgr_queue_done()).
44
/* qmgr_entry_done() triggers special action when the last in-core
45
/* queue entry for a message is done with: either read more
46
/* recipients from the queue file, delete the queue file, or move
47
/* the queue file to the deferred queue; send bounce reports to the
48
/* message originator (see qmgr_active_done()).
50
/* qmgr_entry_select() selects the next entry from the named
51
/* per-site queue's `todo' list for actual delivery. The entry is
52
/* moved to the queue's `busy' list: the list of messages being
55
/* qmgr_entry_unselect() takes the named entry off the named
56
/* per-site queue's `busy' list and moves it to the queue's
59
/* Panic: interface violations, internal inconsistencies.
63
/* The Secure Mailer license must be distributed with this software.
66
/* IBM T.J. Watson Research
68
/* Yorktown Heights, NY 10598, USA
77
/* Utility library. */
86
#include <mail_params.h>
88
/* Application-specific. */
92
/* qmgr_entry_select - select queue entry for delivery */
94
QMGR_ENTRY *qmgr_entry_select(QMGR_QUEUE *queue)
98
if ((entry = queue->todo.prev) != 0) {
99
QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry);
100
queue->todo_refcount--;
101
QMGR_LIST_APPEND(queue->busy, entry);
102
queue->busy_refcount++;
107
/* qmgr_entry_unselect - unselect queue entry for delivery */
109
void qmgr_entry_unselect(QMGR_QUEUE *queue, QMGR_ENTRY *entry)
111
QMGR_LIST_UNLINK(queue->busy, QMGR_ENTRY *, entry);
112
queue->busy_refcount--;
113
QMGR_LIST_APPEND(queue->todo, entry);
114
queue->todo_refcount++;
117
/* qmgr_entry_done - dispose of queue entry */
119
void qmgr_entry_done(QMGR_ENTRY *entry, int which)
121
QMGR_QUEUE *queue = entry->queue;
122
QMGR_MESSAGE *message = entry->message;
125
* Take this entry off the in-core queue.
127
if (entry->stream != 0)
128
msg_panic("qmgr_entry_done: file is open");
129
if (which == QMGR_QUEUE_BUSY) {
130
QMGR_LIST_UNLINK(queue->busy, QMGR_ENTRY *, entry);
131
queue->busy_refcount--;
132
} else if (which == QMGR_QUEUE_TODO) {
133
QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry);
134
queue->todo_refcount--;
136
msg_panic("qmgr_entry_done: bad queue spec: %d", which);
140
* Free the recipient list and decrease the in-core recipient count
143
qmgr_recipient_count -= entry->rcpt_list.len;
144
qmgr_rcpt_list_free(&entry->rcpt_list);
146
myfree((char *) entry);
149
* When the in-core queue for this site is empty and when this site is
150
* not dead, discard the in-core queue. When this site is dead, but the
151
* number of in-core queues exceeds some threshold, get rid of this
152
* in-core queue anyway, in order to avoid running out of memory.
154
if (queue->todo.next == 0 && queue->busy.next == 0) {
155
if (queue->window == 0 && qmgr_queue_count > 2 * var_qmgr_rcpt_limit)
156
qmgr_queue_unthrottle(queue);
157
if (queue->window > 0)
158
qmgr_queue_done(queue);
162
* Update the in-core message reference count. When the in-core message
163
* structure has no more references, dispose of the message.
165
* When the in-core recipient count falls below a threshold, and this
166
* message has more recipients, read more recipients now. If we read more
167
* recipients as soon as the recipient count falls below the in-core
168
* recipient limit, we do not give other messages a chance until this
169
* message is delivered. That's good for mailing list deliveries, bad for
170
* one-to-one mail. If we wait until the in-core recipient count drops
171
* well below the in-core recipient limit, we give other mail a chance,
172
* but we also allow list deliveries to become interleaved. In the worst
173
* case, people near the start of a mailing list get a burst of postings
174
* today, while people near the end of the list get that same burst of
175
* postings a whole day later.
177
#define FUDGE(x) ((x) * (var_qmgr_fudge / 100.0))
179
if (message->rcpt_offset > 0
180
&& qmgr_recipient_count < FUDGE(var_qmgr_rcpt_limit))
181
qmgr_message_realloc(message);
182
if (message->refcount == 0)
183
qmgr_active_done(message);
186
/* qmgr_entry_create - create queue todo entry */
188
QMGR_ENTRY *qmgr_entry_create(QMGR_QUEUE *queue, QMGR_MESSAGE *message)
195
if (queue->window == 0)
196
msg_panic("qmgr_entry_create: dead queue: %s", queue->name);
199
* Create the delivery request.
201
entry = (QMGR_ENTRY *) mymalloc(sizeof(QMGR_ENTRY));
203
entry->message = message;
204
qmgr_rcpt_list_init(&entry->rcpt_list);
206
entry->queue = queue;
207
QMGR_LIST_APPEND(queue->todo, entry);
208
queue->todo_refcount++;
211
* Warn if a destination is falling behind while the active queue
212
* contains a non-trivial amount of single-recipient email. When a
213
* destination takes up more and more space in the active queue, then
214
* other mail will not get through and delivery performance will suffer.
216
* XXX At this point in the code, the busy reference count is still less
217
* than the concurrency limit (otherwise this code would not be invoked
218
* in the first place) so we have to make make some awkward adjustments
221
* XXX The queue length test below looks at the active queue share of an
222
* individual destination. This catches the case where mail for one
223
* destination is falling behind because it has to round-robin compete
224
* with many other destinations. However, Postfix will also perform
225
* poorly when most of the active queue is tied up by a small number of
226
* concurrency limited destinations. The queue length test below detects
227
* such conditions only indirectly.
229
* XXX This code does not detect the case that the active queue is being
230
* starved because incoming mail is pounding the disk.
232
if (var_helpful_warnings && var_qmgr_clog_warn_time > 0) {
233
int queue_length = queue->todo_refcount + queue->busy_refcount;
235
QMGR_TRANSPORT *transport;
238
if (queue_length > var_qmgr_active_limit / 5
239
&& (now = event_time()) >= queue->clog_time_to_warn) {
240
active_share = queue_length / (double) qmgr_message_count;
241
msg_warn("mail for %s is using up %d of %d active queue entries",
242
queue->nexthop, queue_length, qmgr_message_count);
243
if (active_share < 0.9)
244
msg_warn("this may slow down other mail deliveries");
245
transport = queue->transport;
246
if (transport->dest_concurrency_limit > 0
247
&& transport->dest_concurrency_limit <= queue->busy_refcount + 1)
248
msg_warn("you may need to increase the main.cf %s%s from %d",
249
transport->name, _DEST_CON_LIMIT,
250
transport->dest_concurrency_limit);
251
else if (queue->window > var_qmgr_active_limit * active_share)
252
msg_warn("you may need to increase the main.cf %s from %d",
253
VAR_QMGR_ACT_LIMIT, var_qmgr_active_limit);
254
else if (queue->peers.next != queue->peers.prev)
255
msg_warn("you may need a separate master.cf transport for %s",
258
msg_warn("you may need to reduce %s connect and helo timeouts",
260
msg_warn("so that Postfix quickly skips unavailable hosts");
261
msg_warn("you may need to increase the main.cf %s and %s",
262
VAR_MIN_BACKOFF_TIME, VAR_MAX_BACKOFF_TIME);
263
msg_warn("so that Postfix wastes less time on undeliverable mail");
264
msg_warn("you may need to increase the master.cf %s process limit",
267
msg_warn("please avoid flushing the whole queue when you have");
268
msg_warn("lots of deferred mail, that is bad for performance");
269
msg_warn("to turn off these warnings specify: %s = 0",
270
VAR_QMGR_CLOG_WARN_TIME);
271
queue->clog_time_to_warn = now + var_qmgr_clog_warn_time;