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  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 */
176 int
177 Configuration::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 */
237 int 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 
296 int 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 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