XRootD
Loading...
Searching...
No Matches
XrdThrottleConfig.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* (c) 2025 by the Morgridge Institute for Research */
4/* */
5/* This file is part of the XRootD software suite. */
6/* */
7/* XRootD is free software: you can redistribute it and/or modify it under */
8/* the terms of the GNU Lesser General Public License as published by the */
9/* Free Software Foundation, either version 3 of the License, or (at your */
10/* option) any later version. */
11/* */
12/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
13/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
14/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
15/* License for more details. */
16/* */
17/* You should have received a copy of the GNU Lesser General Public License */
18/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
19/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
20/* */
21/* The copyright holder's institutional names and contributor's names may not */
22/* be used to endorse or promote products derived from this software without */
23/* specific prior written permission of the institution or contributor. */
24/******************************************************************************/
25
26#include "XrdOuc/XrdOuca2x.hh"
27#include "XrdOuc/XrdOucEnv.hh"
29#include "XrdSys/XrdSysError.hh"
32
33#include <cstring>
34#include <string>
35#include <fcntl.h>
36
37using namespace XrdThrottle;
38
39#define TS_Xeq(key, func) NoGo = (strcmp(key, var) == 0) ? func(Config) : 0
40int
41Configuration::Configure(const std::string &config_file)
42{
43 XrdOucEnv myEnv;
44 XrdOucStream Config(&m_log, getenv("XRDINSTANCE"), &myEnv, "(Throttle Config)> ");
45 int cfgFD;
46 if (config_file.empty()) {
47 m_log.Say("No filename specified.");
48 return 1;
49 }
50 if ((cfgFD = open(config_file.c_str(), O_RDONLY)) < 0) {
51 m_log.Emsg("Config", errno, "Unable to open configuration file", config_file.c_str());
52 return 1;
53 }
54 Config.Attach(cfgFD);
55 static const char *cvec[] = { "*** throttle (ofs) plugin config:", 0 };
56 Config.Capture(cvec);
57
58 char *var, *val;
59 int NoGo = 0;
60 while( (var = Config.GetMyFirstWord()) )
61 {
62 if (!strcmp("throttle.fslib", var)) {
63 val = Config.GetWord();
64 if (!val || !val[0]) {m_log.Emsg("Config", "fslib not specified."); continue;}
65 m_fslib = val;
66 }
67 TS_Xeq("throttle.max_open_files", xmaxopen);
68 TS_Xeq("throttle.max_active_connections", xmaxconn);
69 TS_Xeq("throttle.throttle", xthrottle);
70 TS_Xeq("throttle.loadshed", xloadshed);
71 TS_Xeq("throttle.max_wait_time", xmaxwait);
72 TS_Xeq("throttle.trace", xtrace);
73 if (NoGo)
74 {
75 m_log.Emsg("Config", "Throttle configuration failed.");
76 return 1;
77 }
78 }
79 return 0;
80}
81
82/******************************************************************************/
83/* x m a x o p e n */
84/******************************************************************************/
85
86/* Function: xmaxopen
87
88 Purpose: Parse the directive: throttle.max_open_files <limit>
89
90 <limit> maximum number of open file handles for a unique entity.
91
92 Output: 0 upon success or !0 upon failure.
93*/
94int
95Configuration::xmaxopen(XrdOucStream &Config)
96{
97 auto val = Config.GetWord();
98 if (!val || val[0] == '\0')
99 {m_log.Emsg("Config", "Max open files not specified! Example usage: throttle.max_open_files 16000");}
100 long long max_open = -1;
101 if (XrdOuca2x::a2sz(m_log, "max open files value", val, &max_open, 1)) return 1;
102
103 m_max_open = max_open;
104 return 0;
105}
106
107
108/******************************************************************************/
109/* x m a x c o n n */
110/******************************************************************************/
111
112/* Function: xmaxconn
113
114 Purpose: Parse the directive: throttle.max_active_connections <limit>
115
116 <limit> maximum number of connections with at least one open file for a given entity
117
118 Output: 0 upon success or !0 upon failure.
119*/
120int
121Configuration::xmaxconn(XrdOucStream &Config)
122{
123 auto val = Config.GetWord();
124 if (!val || val[0] == '\0')
125 {m_log.Emsg("Config", "Max active connections not specified! Example usage: throttle.max_active_connections 4000");}
126 long long max_conn = -1;
127 if (XrdOuca2x::a2sz(m_log, "max active connections value", val, &max_conn, 1)) return 1;
128
129 m_max_conn = max_conn;
130 return 0;
131}
132
133/******************************************************************************/
134/* x m a x w a i t */
135/******************************************************************************/
136
137/* Function: xmaxwait
138
139 Purpose: Parse the directive: throttle.max_wait_time <limit>
140
141 <limit> maximum wait time, in seconds, before an operation should fail
142
143 If the directive is not provided, the default is 30 seconds.
144
145 Output: 0 upon success or !0 upon failure.
146*/
147int
148Configuration::xmaxwait(XrdOucStream &Config)
149{
150 auto val = Config.GetWord();
151 if (!val || val[0] == '\0')
152 {m_log.Emsg("Config", "Max waiting time not specified (must be in seconds)! Example usage: throttle.max_wait_time 20");}
153 long long max_wait = -1;
154 if (XrdOuca2x::a2sz(m_log, "max waiting time value", val, &max_wait, 1)) return 1;
155
156 return 0;
157}
158
159/******************************************************************************/
160/* x t h r o t t l e */
161/******************************************************************************/
162
163/* Function: xthrottle
164
165 Purpose: To parse the directive: throttle [data <drate>] [iops <irate>] [concurrency <climit>] [interval <rint>]
166
167 <drate> maximum bytes per second through the server.
168 <irate> maximum IOPS per second through the server.
169 <climit> maximum number of concurrent IO connections.
170 <rint> minimum interval in milliseconds between throttle re-computing.
171
172 Output: 0 upon success or !0 upon failure.
173*/
174int
175Configuration::xthrottle(XrdOucStream &Config)
176{
177 long long drate = -1, irate = -1, rint = 1000, climit = -1;
178 char *val;
179
180 while ((val = Config.GetWord()))
181 {
182 if (strcmp("data", val) == 0)
183 {
184 if (!(val = Config.GetWord()))
185 {m_log.Emsg("Config", "data throttle limit not specified."); return 1;}
186 if (XrdOuca2x::a2sz(m_log,"data throttle value",val,&drate,1)) return 1;
187 }
188 else if (strcmp("iops", val) == 0)
189 {
190 if (!(val = Config.GetWord()))
191 {m_log.Emsg("Config", "IOPS throttle limit not specified."); return 1;}
192 if (XrdOuca2x::a2sz(m_log,"IOPS throttle value",val,&irate,1)) return 1;
193 }
194 else if (strcmp("rint", val) == 0)
195 {
196 if (!(val = Config.GetWord()))
197 {m_log.Emsg("Config", "recompute interval not specified (in ms)."); return 1;}
198 if (XrdOuca2x::a2sp(m_log,"recompute interval value (in ms)",val,&rint,10)) return 1;
199 }
200 else if (strcmp("concurrency", val) == 0)
201 {
202 if (!(val = Config.GetWord()))
203 {m_log.Emsg("Config", "Concurrency limit not specified."); return 1;}
204 if (XrdOuca2x::a2sz(m_log,"Concurrency limit value",val,&climit,1)) return 1;
205 }
206 else
207 {
208 m_log.Emsg("Config", "Warning - unknown throttle option specified", val, ".");
209 }
210 }
211
212 m_throttle_data_rate = drate;
213 m_throttle_iops_rate = irate;
214 m_throttle_concurrency_limit = climit;
215 m_throttle_recompute_interval_ms = rint;
216
217 return 0;
218}
219
220/******************************************************************************/
221/* x l o a d s h e d */
222/******************************************************************************/
223
224/* Function: xloadshed
225
226 Purpose: To parse the directive: loadshed host <hostname> [port <port>] [frequency <freq>]
227
228 <hostname> hostname of server to shed load to. Required
229 <port> port of server to shed load to. Defaults to 1094
230 <freq> A value from 1 to 100 specifying how often to shed load
231 (1 = 1% chance; 100 = 100% chance; defaults to 10).
232
233 Output: 0 upon success or !0 upon failure.
234*/
235int Configuration::xloadshed(XrdOucStream &Config)
236{
237 long long port = 0, freq = 0;
238 char *val;
239 std::string hostname;
240
241 while ((val = Config.GetWord()))
242 {
243 if (strcmp("host", val) == 0)
244 {
245 if (!(val = Config.GetWord()))
246 {m_log.Emsg("Config", "loadshed hostname not specified."); return 1;}
247 hostname = val;
248 }
249 else if (strcmp("port", val) == 0)
250 {
251 if (!(val = Config.GetWord()))
252 {m_log.Emsg("Config", "Port number not specified."); return 1;}
253 if (XrdOuca2x::a2sz(m_log,"Port number",val,&port,1, 65536)) return 1;
254 }
255 else if (strcmp("frequency", val) == 0)
256 {
257 if (!(val = Config.GetWord()))
258 {m_log.Emsg("Config", "Loadshed frequency not specified."); return 1;}
259 if (XrdOuca2x::a2sz(m_log,"Loadshed frequency",val,&freq,1,100)) return 1;
260 }
261 else
262 {
263 m_log.Emsg("Config", "Warning - unknown loadshed option specified", val, ".");
264 }
265 }
266
267 if (hostname.empty())
268 {
269 m_log.Emsg("Config", "must specify hostname for loadshed parameter.");
270 return 1;
271 }
272
273 m_loadshed_freq = freq;
274 m_loadshed_hostname = hostname;
275 m_loadshed_port = port;
276
277 return 0;
278}
279
280/******************************************************************************/
281/* x t r a c e */
282/******************************************************************************/
283
284/* Function: xtrace
285
286 Purpose: To parse the directive: trace <events>
287
288 <events> the blank separated list of events to trace. Trace
289 directives are cummalative.
290
291 Output: 0 upon success or 1 upon failure.
292*/
293
294int Configuration::xtrace(XrdOucStream &Config)
295{
296 char *val;
297 static const struct traceopts {const char *opname; int opval;} tropts[] =
298 {
299 {"all", TRACE_ALL},
300 {"off", TRACE_NONE},
301 {"none", TRACE_NONE},
302 {"debug", TRACE_DEBUG},
303 {"iops", TRACE_IOPS},
304 {"bandwidth", TRACE_BANDWIDTH},
305 {"ioload", TRACE_IOLOAD},
306 {"files", TRACE_FILES},
307 {"connections",TRACE_CONNS},
308 };
309 int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
310
311 if (!(val = Config.GetWord()))
312 {
313 m_log.Emsg("Config", "trace option not specified");
314 return 1;
315 }
316 while (val)
317 {
318 if (!strcmp(val, "off"))
319 {
320 trval = 0;
321 }
322 else
323 {
324 if ((neg = (val[0] == '-' && val[1])))
325 {
326 val++;
327 }
328 for (i = 0; i < numopts; i++)
329 {
330 if (!strcmp(val, tropts[i].opname))
331 {
332 if (neg)
333 {
334 if (tropts[i].opval) trval &= ~tropts[i].opval;
335 else trval = TRACE_ALL;
336 }
337 else if (tropts[i].opval) trval |= tropts[i].opval;
338 else trval = TRACE_NONE;
339 break;
340 }
341 }
342 if (i >= numopts)
343 {
344 m_log.Say("Config warning: ignoring invalid trace option '", val, "'.");
345 }
346 }
347 val = Config.GetWord();
348 }
349 m_trace_levels = trval;
350 return 0;
351}
#define TS_Xeq(x, m)
Definition XrdConfig.cc:160
#define open
Definition XrdPosix.hh:76
#define TRACE_IOLOAD
#define TRACE_BANDWIDTH
#define TRACE_FILES
#define TRACE_CONNS
#define TRACE_IOPS
#define TRACE_NONE
Definition XrdTrace.hh:34
#define TRACE_DEBUG
Definition XrdTrace.hh:36
#define TRACE_ALL
Definition XrdTrace.hh:35
static int a2sp(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition XrdOuca2x.cc:213
static int a2sz(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition XrdOuca2x.cc:257
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
int Configure(const std::string &config_file)
XrdCmsConfig Config