7 /* delivery agent feedback management
11 /* void qmgr_feedback_init(fbck_ctl, name_prefix, name_tail,
12 /* def_name, def_value)
13 /* QMGR_FEEDBACK *fbck_ctl;
14 /* const char *name_prefix;
15 /* const char *name_tail;
16 /* const char *def_name;
17 /* const char *def_value;
19 /* double QMGR_FEEDBACK_VAL(fbck_ctl, concurrency)
20 /* QMGR_FEEDBACK *fbck_ctl;
21 /* const int concurrency;
23 /* Upon completion of a delivery request, a delivery agent
24 /* provides a hint that the scheduler should dedicate fewer or
25 /* more resources to a specific destination.
27 /* qmgr_feedback_init() looks up transport-dependent positive
28 /* or negative concurrency feedback control information from
29 /* main.cf, and converts it to internal form.
31 /* QMGR_FEEDBACK_VAL() computes a concurrency adjustment based
32 /* on a preprocessed feedback control information and the
33 /* current concurrency window. This is an "unsafe" macro that
34 /* evaluates some arguments multiple times.
38 /* Pointer to QMGR_FEEDBACK structure where the result will
41 /* Mail delivery transport name, used as the initial portion
42 /* of a transport-dependent concurrency feedback parameter
45 /* The second, and fixed, portion of a transport-dependent
46 /* concurrency feedback parameter.
48 /* The name of a default feedback parameter.
50 /* The value of the default feedback parameter.
52 /* Delivery concurrency for concurrency-dependent feedback calculation.
54 /* Warning: configuration error or unreasonable input. The program
55 /* uses name_tail feedback instead.
56 /* Panic: consistency check failure.
60 /* The Secure Mailer license must be distributed with this software.
63 /* IBM T.J. Watson Research
65 /* Yorktown Heights, NY 10598, USA
72 #include <limits.h> /* INT_MAX */
73 #include <stdio.h> /* sscanf() */
76 /* Utility library. */
79 #include <name_code.h>
80 #include <stringops.h>
85 #include <mail_params.h>
86 #include <mail_conf.h>
88 /* Application-specific. */
93 * Lookup tables for main.cf feedback method names.
95 const NAME_CODE qmgr_feedback_map
[] = {
96 CONC_FDBACK_NAME_WIN
, QMGR_FEEDBACK_IDX_WIN
,
97 #ifdef QMGR_FEEDBACK_IDX_SQRT_WIN
98 CONC_FDBACK_NAME_SQRT_WIN
, QMGR_FEEDBACK_IDX_SQRT_WIN
,
100 0, QMGR_FEEDBACK_IDX_NONE
,
103 /* qmgr_feedback_init - initialize feedback control */
105 void qmgr_feedback_init(QMGR_FEEDBACK
*fb
,
106 const char *name_prefix
,
107 const char *name_tail
,
108 const char *def_name
,
112 char denom_str
[30 + 1];
120 * Look up the transport-dependent feedback value.
122 fbck_name
= concatenate(name_prefix
, name_tail
, (char *) 0);
123 fbck_val
= get_mail_conf_str(fbck_name
, def_val
, 1, 0);
126 * We allow users to express feedback as 1/8, as a more user-friendly
127 * alternative to 0.125 (or worse, having users specify the number of
128 * events in a feedback hysteresis cycle).
130 * We use some sscanf() fu to parse the value into numerator and optional
131 * "/" followed by denominator. We're doing this only a few times during
132 * the process life time, so we strive for convenience instead of speed.
134 #define INCLUSIVE_BOUNDS(val, low, high) ((val) >= (low) && (val) <= (high))
136 fb
->hysteresis
= 1; /* legacy */
137 fb
->base
= -1; /* assume error */
139 switch (sscanf(fbck_val
, "%lf %1[/] %30s%c",
140 &enum_val
, &slash
, denom_str
, &junk
)) {
142 fb
->index
= QMGR_FEEDBACK_IDX_NONE
;
146 if ((fb
->index
= name_code(qmgr_feedback_map
, NAME_CODE_FLAG_NONE
,
147 denom_str
)) != QMGR_FEEDBACK_IDX_NONE
) {
149 } else if (INCLUSIVE_BOUNDS(enum_val
, 0, INT_MAX
)
150 && sscanf(denom_str
, "%lf%c", &denom_val
, &junk
) == 1
151 && INCLUSIVE_BOUNDS(denom_val
, 1.0 / INT_MAX
, INT_MAX
)) {
152 fb
->base
= enum_val
/ denom_val
;
158 * Sanity check. If input is bad, we just warn and use a reasonable
161 if (!INCLUSIVE_BOUNDS(fb
->base
, 0, 1)) {
162 msg_warn("%s: ignoring malformed or unreasonable feedback: %s",
163 strcmp(fbck_val
, def_val
) ? fbck_name
: def_name
, fbck_val
);
164 fb
->index
= QMGR_FEEDBACK_IDX_NONE
;
169 * Performance debugging/analysis.
171 if (var_conc_feedback_debug
)
172 msg_info("%s: %s feedback type %d value at %d: %g",
173 name_prefix
, strcmp(fbck_val
, def_val
) ?
174 fbck_name
: def_name
, fb
->index
, var_init_dest_concurrency
,
175 QMGR_FEEDBACK_VAL(*fb
, var_init_dest_concurrency
));