XRootD
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"
28 #include "XrdOuc/XrdOucStream.hh"
29 #include "XrdSys/XrdSysError.hh"
32 
33 #include <cstring>
34 #include <string>
35 #include <fcntl.h>
36 
37 using namespace XrdThrottle;
38 
39 #define TS_Xeq(key, func) NoGo = (strcmp(key, var) == 0) ? func(Config) : 0
40 int
41 Configuration::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 */
94 int
95 Configuration::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 */
120 int
121 Configuration::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 */
147 int
148 Configuration::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 */
174 int
175 Configuration::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 */
235 int 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 
294 int 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 open
Definition: XrdPosix.hh:76
#define TS_Xeq(key, func)
#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)
Definition: XrdSysError.cc:95
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:141
int Configure(const std::string &config_file)
XrdCmsConfig Config