No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / qmgr / qmgr_feedback.c
blob8959ced544b962d752df0c9125dede7a6c5d4362
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* qmgr_feedback 3
6 /* SUMMARY
7 /* delivery agent feedback management
8 /* SYNOPSIS
9 /* #include "qmgr.h"
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;
22 /* DESCRIPTION
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.
36 /* Arguments:
37 /* .IP fbck_ctl
38 /* Pointer to QMGR_FEEDBACK structure where the result will
39 /* be stored.
40 /* .IP name_prefix
41 /* Mail delivery transport name, used as the initial portion
42 /* of a transport-dependent concurrency feedback parameter
43 /* name.
44 /* .IP name_tail
45 /* The second, and fixed, portion of a transport-dependent
46 /* concurrency feedback parameter.
47 /* .IP def_name
48 /* The name of a default feedback parameter.
49 /* .IP def_val
50 /* The value of the default feedback parameter.
51 /* .IP concurrency
52 /* Delivery concurrency for concurrency-dependent feedback calculation.
53 /* DIAGNOSTICS
54 /* Warning: configuration error or unreasonable input. The program
55 /* uses name_tail feedback instead.
56 /* Panic: consistency check failure.
57 /* LICENSE
58 /* .ad
59 /* .fi
60 /* The Secure Mailer license must be distributed with this software.
61 /* AUTHOR(S)
62 /* Wietse Venema
63 /* IBM T.J. Watson Research
64 /* P.O. Box 704
65 /* Yorktown Heights, NY 10598, USA
66 /*--*/
68 /* System library. */
70 #include <sys_defs.h>
71 #include <stdlib.h>
72 #include <limits.h> /* INT_MAX */
73 #include <stdio.h> /* sscanf() */
74 #include <string.h>
76 /* Utility library. */
78 #include <msg.h>
79 #include <name_code.h>
80 #include <stringops.h>
81 #include <mymalloc.h>
83 /* Global library. */
85 #include <mail_params.h>
86 #include <mail_conf.h>
88 /* Application-specific. */
90 #include "qmgr.h"
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,
99 #endif
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,
109 const char *def_val)
111 double enum_val;
112 char denom_str[30 + 1];
113 double denom_val;
114 char slash;
115 char junk;
116 char *fbck_name;
117 char *fbck_val;
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)) {
141 case 1:
142 fb->index = QMGR_FEEDBACK_IDX_NONE;
143 fb->base = enum_val;
144 break;
145 case 3:
146 if ((fb->index = name_code(qmgr_feedback_map, NAME_CODE_FLAG_NONE,
147 denom_str)) != QMGR_FEEDBACK_IDX_NONE) {
148 fb->base = enum_val;
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;
154 break;
158 * Sanity check. If input is bad, we just warn and use a reasonable
159 * default.
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;
165 fb->base = 1;
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));
177 myfree(fbck_name);
178 myfree(fbck_val);