xref: /netbsd-src/external/ibm-public/postfix/dist/src/qmgr/qmgr_feedback.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: qmgr_feedback.c,v 1.2 2022/10/08 16:12:48 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	qmgr_feedback 3
6 /* SUMMARY
7 /*	delivery agent feedback management
8 /* SYNOPSIS
9 /*	#include "qmgr.h"
10 /*
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;
18 /*
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.
26 /*
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.
30 /*
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.
35 /*
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 /*
67 /*	Wietse Venema
68 /*	Google, Inc.
69 /*	111 8th Avenue
70 /*	New York, NY 10011, USA
71 /*--*/
72 
73 /* System library. */
74 
75 #include <sys_defs.h>
76 #include <stdlib.h>
77 #include <limits.h>			/* INT_MAX */
78 #include <stdio.h>			/* sscanf() */
79 #include <string.h>
80 
81 /* Utility library. */
82 
83 #include <msg.h>
84 #include <name_code.h>
85 #include <stringops.h>
86 #include <mymalloc.h>
87 
88 /* Global library. */
89 
90 #include <mail_params.h>
91 #include <mail_conf.h>
92 
93 /* Application-specific. */
94 
95 #include "qmgr.h"
96 
97  /*
98   * Lookup tables for main.cf feedback method names.
99   */
100 const NAME_CODE qmgr_feedback_map[] = {
101     CONC_FDBACK_NAME_WIN, QMGR_FEEDBACK_IDX_WIN,
102 #ifdef QMGR_FEEDBACK_IDX_SQRT_WIN
103     CONC_FDBACK_NAME_SQRT_WIN, QMGR_FEEDBACK_IDX_SQRT_WIN,
104 #endif
105     0, QMGR_FEEDBACK_IDX_NONE,
106 };
107 
108 /* qmgr_feedback_init - initialize feedback control */
109 
qmgr_feedback_init(QMGR_FEEDBACK * fb,const char * name_prefix,const char * name_tail,const char * def_name,const char * def_val)110 void    qmgr_feedback_init(QMGR_FEEDBACK *fb,
111 			           const char *name_prefix,
112 			           const char *name_tail,
113 			           const char *def_name,
114 			           const char *def_val)
115 {
116     double  enum_val;
117     char    denom_str[30 + 1];
118     double  denom_val;
119     char    slash[1 + 1];
120     char    junk;
121     char   *fbck_name;
122     char   *fbck_val;
123 
124     /*
125      * Look up the transport-dependent feedback value.
126      */
127     fbck_name = concatenate(name_prefix, name_tail, (char *) 0);
128     fbck_val = get_mail_conf_str(fbck_name, def_val, 1, 0);
129 
130     /*
131      * We allow users to express feedback as 1/8, as a more user-friendly
132      * alternative to 0.125 (or worse, having users specify the number of
133      * events in a feedback hysteresis cycle).
134      *
135      * We use some sscanf() fu to parse the value into numerator and optional
136      * "/" followed by denominator. We're doing this only a few times during
137      * the process life time, so we strive for convenience instead of speed.
138      */
139 #define INCLUSIVE_BOUNDS(val, low, high) ((val) >= (low) && (val) <= (high))
140 
141     fb->hysteresis = 1;				/* legacy */
142     fb->base = -1;				/* assume error */
143 
144     switch (sscanf(fbck_val, "%lf %1[/] %30s%c",
145 		   &enum_val, slash, denom_str, &junk)) {
146     case 1:
147 	fb->index = QMGR_FEEDBACK_IDX_NONE;
148 	fb->base = enum_val;
149 	break;
150     case 3:
151 	if ((fb->index = name_code(qmgr_feedback_map, NAME_CODE_FLAG_NONE,
152 				   denom_str)) != QMGR_FEEDBACK_IDX_NONE) {
153 	    fb->base = enum_val;
154 	} else if (INCLUSIVE_BOUNDS(enum_val, 0, INT_MAX)
155 		   && sscanf(denom_str, "%lf%c", &denom_val, &junk) == 1
156 		   && INCLUSIVE_BOUNDS(denom_val, 1.0 / INT_MAX, INT_MAX)) {
157 	    fb->base = enum_val / denom_val;
158 	}
159 	break;
160     }
161 
162     /*
163      * Sanity check. If input is bad, we just warn and use a reasonable
164      * default.
165      */
166     if (!INCLUSIVE_BOUNDS(fb->base, 0, 1)) {
167 	msg_warn("%s: ignoring malformed or unreasonable feedback: %s",
168 		 strcmp(fbck_val, def_val) ? fbck_name : def_name, fbck_val);
169 	fb->index = QMGR_FEEDBACK_IDX_NONE;
170 	fb->base = 1;
171     }
172 
173     /*
174      * Performance debugging/analysis.
175      */
176     if (var_conc_feedback_debug)
177 	msg_info("%s: %s feedback type %d value at %d: %g",
178 		 name_prefix, strcmp(fbck_val, def_val) ?
179 		 fbck_name : def_name, fb->index, var_init_dest_concurrency,
180 		 QMGR_FEEDBACK_VAL(*fb, var_init_dest_concurrency));
181 
182     myfree(fbck_name);
183     myfree(fbck_val);
184 }
185