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 m_max_wait = max_wait;
157
158 return 0;
159}
160
161/******************************************************************************/
162/* x t h r o t t l e */
163/******************************************************************************/
164
165/* Function: xthrottle
166
167 Purpose: To parse the directive: throttle [data <drate>] [iops <irate>] [concurrency <climit>] [interval <rint>]
168
169 <drate> maximum bytes per second through the server.
170 <irate> maximum IOPS per second through the server.
171 <climit> maximum number of concurrent IO connections.
172 <rint> minimum interval in milliseconds between throttle re-computing.
173
174 Output: 0 upon success or !0 upon failure.
175*/
176int
177Configuration::xthrottle(XrdOucStream &Config)
178{
179 long long drate = -1, irate = -1, rint = 1000, climit = -1;
180 char *val;
181
182 while ((val = Config.GetWord()))
183 {
184 if (strcmp("data", val) == 0)
185 {
186 if (!(val = Config.GetWord()))
187 {m_log.Emsg("Config", "data throttle limit not specified."); return 1;}
188 if (XrdOuca2x::a2sz(m_log,"data throttle value",val,&drate,1)) return 1;
189 }
190 else if (strcmp("iops", val) == 0)
191 {
192 if (!(val = Config.GetWord()))
193 {m_log.Emsg("Config", "IOPS throttle limit not specified."); return 1;}
194 if (XrdOuca2x::a2sz(m_log,"IOPS throttle value",val,&irate,1)) return 1;
195 }
196 else if (strcmp("rint", val) == 0)
197 {
198 if (!(val = Config.GetWord()))
199 {m_log.Emsg("Config", "recompute interval not specified (in ms)."); return 1;}
200 if (XrdOuca2x::a2sp(m_log,"recompute interval value (in ms)",val,&rint,10)) return 1;
201 }
202 else if (strcmp("concurrency", val) == 0)
203 {
204 if (!(val = Config.GetWord()))
205 {m_log.Emsg("Config", "Concurrency limit not specified."); return 1;}
206 if (XrdOuca2x::a2sz(m_log,"Concurrency limit value",val,&climit,1)) return 1;
207 }
208 else
209 {
210 m_log.Emsg("Config", "Warning - unknown throttle option specified", val, ".");
211 }
212 }
213
214 m_throttle_data_rate = drate;
215 m_throttle_iops_rate = irate;
216 m_throttle_concurrency_limit = climit;
217 m_throttle_recompute_interval_ms = rint;
218
219 return 0;
220}
221
222/******************************************************************************/
223/* x l o a d s h e d */
224/******************************************************************************/
225
226/* Function: xloadshed
227
228 Purpose: To parse the directive: loadshed host <hostname> [port <port>] [frequency <freq>]
229
230 <hostname> hostname of server to shed load to. Required
231 <port> port of server to shed load to. Defaults to 1094
232 <freq> A value from 1 to 100 specifying how often to shed load
233 (1 = 1% chance; 100 = 100% chance; defaults to 10).
234
235 Output: 0 upon success or !0 upon failure.
236*/
237int Configuration::xloadshed(XrdOucStream &Config)
238{
239 long long port = 0, freq = 0;
240 char *val;
241 std::string hostname;
242
243 while ((val = Config.GetWord()))
244 {
245 if (strcmp("host", val) == 0)
246 {
247 if (!(val = Config.GetWord()))
248 {m_log.Emsg("Config", "loadshed hostname not specified."); return 1;}
249 hostname = val;
250 }
251 else if (strcmp("port", val) == 0)
252 {
253 if (!(val = Config.GetWord()))
254 {m_log.Emsg("Config", "Port number not specified."); return 1;}
255 if (XrdOuca2x::a2sz(m_log,"Port number",val,&port,1, 65536)) return 1;
256 }
257 else if (strcmp("frequency", val) == 0)
258 {
259 if (!(val = Config.GetWord()))
260 {m_log.Emsg("Config", "Loadshed frequency not specified."); return 1;}
261 if (XrdOuca2x::a2sz(m_log,"Loadshed frequency",val,&freq,1,100)) return 1;
262 }
263 else
264 {
265 m_log.Emsg("Config", "Warning - unknown loadshed option specified", val, ".");
266 }
267 }
268
269 if (hostname.empty())
270 {
271 m_log.Emsg("Config", "must specify hostname for loadshed parameter.");
272 return 1;
273 }
274
275 m_loadshed_freq = freq;
276 m_loadshed_hostname = hostname;
277 m_loadshed_port = port;
278
279 return 0;
280}
281
282/******************************************************************************/
283/* x t r a c e */
284/******************************************************************************/
285
286/* Function: xtrace
287
288 Purpose: To parse the directive: trace <events>
289
290 <events> the blank separated list of events to trace. Trace
291 directives are cummalative.
292
293 Output: 0 upon success or 1 upon failure.
294*/
295
296int Configuration::xtrace(XrdOucStream &Config)
297{
298 char *val;
299 static const struct traceopts {const char *opname; int opval;} tropts[] =
300 {
301 {"all", TRACE_ALL},
302 {"off", TRACE_NONE},
303 {"none", TRACE_NONE},
304 {"debug", TRACE_DEBUG},
305 {"iops", TRACE_IOPS},
306 {"bandwidth", TRACE_BANDWIDTH},
307 {"ioload", TRACE_IOLOAD},
308 {"files", TRACE_FILES},
309 {"connections",TRACE_CONNS},
310 };
311 int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
312
313 if (!(val = Config.GetWord()))
314 {
315 m_log.Emsg("Config", "trace option not specified");
316 return 1;
317 }
318 while (val)
319 {
320 if (!strcmp(val, "off"))
321 {
322 trval = 0;
323 }
324 else
325 {
326 if ((neg = (val[0] == '-' && val[1])))
327 {
328 val++;
329 }
330 for (i = 0; i < numopts; i++)
331 {
332 if (!strcmp(val, tropts[i].opname))
333 {
334 if (neg)
335 {
336 if (tropts[i].opval) trval &= ~tropts[i].opval;
337 else trval = TRACE_ALL;
338 }
339 else if (tropts[i].opval) trval |= tropts[i].opval;
340 else trval = TRACE_NONE;
341 break;
342 }
343 }
344 if (i >= numopts)
345 {
346 m_log.Say("Config warning: ignoring invalid trace option '", val, "'.");
347 }
348 }
349 val = Config.GetWord();
350 }
351 m_trace_levels = trval;
352 return 0;
353}
#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