Skip to content

Commit

Permalink
Add xrootd.fsoverload directive to handle filesystem overloads.
Browse files Browse the repository at this point in the history
The above is mostly for use with a disk caching proxy.
  • Loading branch information
abh3 committed May 23, 2017
1 parent bddc68e commit 404954c
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 39 deletions.
3 changes: 3 additions & 0 deletions src/XProtocol/XProtocol.hh
Expand Up @@ -324,6 +324,7 @@ enum XErrorCode {
kXR_overQuota,
kXR_SigVerErr,
kXR_DecryptErr,
kXR_Overloaded,
kXR_ERRFENCE, // Always last valid errcode + 1
kXR_noErrorYet = 10000
};
Expand Down Expand Up @@ -867,6 +868,7 @@ static int mapError(int rc)
case EDQUOT: return kXR_overQuota;
case EILSEQ: return kXR_SigVerErr;
case ERANGE: return kXR_DecryptErr;
case EUSERS: return kXR_Overloaded;
default: return kXR_FSError;
}
}
Expand Down Expand Up @@ -898,6 +900,7 @@ static int toErrno( int xerr )
case kXR_overQuota: return EDQUOT;
case kXR_SigVerErr: return EILSEQ;
case kXR_DecryptErr: return ERANGE;
case kXR_Overloaded: return EUSERS;
default: return ENOMSG;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/XrdNet/XrdNetUtils.hh
Expand Up @@ -278,7 +278,7 @@ static NetProt NetConfig(NetType netquery=qryINET, const char **eText=0);
//! point to either ']', ':', or a null byte.
//! @param hPort place where the starting address of the port is placed.
//! If no ":port" was found, this will contain *hNend.
//! @param hNend place where the ending address+1 is placed. If no port
//! @param hPend place where the ending address+1 is placed. If no port
//! If no ":port" was found, this will contain *hNend.
//!
//! @return Success: True.
Expand Down
3 changes: 3 additions & 0 deletions src/XrdOuc/XrdOucCache2.hh
Expand Up @@ -240,6 +240,9 @@ XrdOucCache *Create(Parms &Params, XrdOucCacheIO::aprParms *aprP=0)
//! @param mode - Standard mode flags if file is being created.
//!
//! @return <0 Error has occurred, return value is -errno; fail open request.
//! The error code -EUSERS may be returned to trigger overload
//! recovery as specified by the xrootd.fsoverload directive. No
//! other method should return this error code.
//! =0 Continue with open() request.
//! >0 Defer open but treat the file as actually being open. Use the
//! XrdOucCacheIO2::Open() method to open the file at a later time.
Expand Down
39 changes: 39 additions & 0 deletions src/XrdOuc/XrdOucUtils.cc
Expand Up @@ -398,6 +398,45 @@ int XrdOucUtils::is1of(char *val, const char **clist)
return 0;
}

/******************************************************************************/
/* i s F W D */
/******************************************************************************/

int XrdOucUtils::isFWD(const char *path, int *port, char *hBuff, int hBLen,
bool pTrim)
{
const char *hName, *hNend, *hPort, *hPend, *hP = path;
char *eP;
int n;

if (*path == '/') hP++; // Note: It's assumed an objectid if no slash
if (*hP == 'x') hP++;
if (strncmp("root:/", hP, 6)) return 0;
if (hBuff == 0 || hBLen <= 0) return (hP - path) + 6;
hP += 6;

if (!XrdNetUtils::Parse(hP, &hName, &hNend, &hPort, &hPend)) return 0;
if (*hNend == ']') hNend++;
else {if (!(*hNend) && !(hNend = index(hName, '/'))) return 0;
if (!(*hPend)) hPend = hNend;
}

if (pTrim || !(*hPort)) n = hNend - hP;
else n = hPend - hP;
if (n >= hBLen) return 0;
strncpy(hBuff, hP, n);
hBuff[n] = 0;

if (port)
{if (*hNend != ':') *port = 0;
else {*port = strtol(hPort, &eP, 10);
if (*port < 0 || *port > 65535 || eP != hPend) return 0;
}
}

return hPend-path;
}

/******************************************************************************/
/* L o g 2 */
/******************************************************************************/
Expand Down
3 changes: 3 additions & 0 deletions src/XrdOuc/XrdOucUtils.hh
Expand Up @@ -68,6 +68,9 @@ static const char *InstName(const char *name, int Fillit=1);

static int is1of(char *val, const char **clist);

static int isFWD(const char *path, int *port=0, char *hBuff=0, int hBLen=0,
bool pTrim=false);

static int Log2(unsigned long long n);

static int Log10(unsigned long long n);
Expand Down
156 changes: 133 additions & 23 deletions src/XrdXrootd/XrdXrootdConfig.cc
Expand Up @@ -435,6 +435,17 @@ int XrdXrootdProtocol::Configure(char *parms, XrdProtocol_Config *pi)
//
PidFile();

// Finally, check if we really need to be in bypass mode if it is set
//
if (OD_Bypass)
{const char *penv = getenv("XRDXROOTD_PROXY");
if (!penv || *penv != '=')
{OD_Bypass = false;
eDest.Say("Config warning: 'fsoverload bypass' ignored; "
"not a forwarding proxy.");
}
}

// Return success
//
free(adminp);
Expand Down Expand Up @@ -474,6 +485,7 @@ int XrdXrootdProtocol::Config(const char *ConfigFN)
else if TS_Xeq("diglib", xdig);
else if TS_Xeq("export", xexp);
else if TS_Xeq("fslib", xfsl);
else if TS_Xeq("fsoverload", xfso);
else if TS_Xeq("log", xlog);
else if TS_Xeq("monitor", xmon);
else if TS_Xeq("pidpath", xpidf);
Expand Down Expand Up @@ -970,6 +982,81 @@ int XrdXrootdProtocol::xfsL(XrdOucStream &Config, char *val, int lix)
return 0;
}

/******************************************************************************/
/* x f s o */
/******************************************************************************/

/* Function: xfso
Purpose: To parse the directive: fsoverload [options]
options: [[no]bypass] [redirect <host>:<port>[%<prvhost>:<port>]]
[stall <sec>]
bypass If path is a forwarding path, redirect client to the
location specified in the path to bypass this server.
The default is nobypass.
redirect Redirect the request to the specified destination.
stall Stall the client <sec> seconds. The default is 33.
*/

int XrdXrootdProtocol::xfso(XrdOucStream &Config)
{
static const int rHLen = 264;
char rHost[2][rHLen], *hP[2] = {0,0}, *val;
int rPort[2], bypass = -1, stall = -1;

// Process all of the options
//
while((val = Config.GetWord()) && *val)
{ if (!strcmp(val, "bypass")) bypass = 1;
else if (!strcmp(val, "nobypass")) bypass = 0;
else if (!strcmp(val, "redirect"))
{val = Config.GetWord();
if (!xred_php(val, hP, rPort)) return 1;
for (int i = 0; i < 2; i++)
{if (!hP[i]) rHost[i][0] = 0;
else {strlcpy(rHost[i], hP[i], rHLen);
hP[i] = rHost[i];
}
}
}
else if (!strcmp(val, "stall"))
{if (!(val = Config.GetWord()) || !(*val))
{eDest.Emsg("Config", "stall value not specified");
return 1;
}
if (XrdOuca2x::a2tm(eDest,"stall",val,&stall,0,32767))
return 1;
}
else {eDest.Emsg("config","invalid fsoverload option",val); return 1;}
}

// Set all specified values
//
if (bypass >= 0) OD_Bypass = (bypass ? true : false);
if (stall >= 0) OD_Stall = stall;
if (hP[0])
{if (Route[RD_ovld].Host[0]) free(Route[RD_ovld].Host[0]);
if (Route[RD_ovld].Host[1]) free(Route[RD_ovld].Host[1]);
Route[RD_ovld].Host[0] = strdup(hP[0]);
Route[RD_ovld].Port[0] = rPort[0];
Route[RD_ovld].RDSz[0] = strlen(hP[0]);
if (hP[1])
{Route[RD_ovld].Host[1] = strdup(hP[1]);
Route[RD_ovld].Port[1] = rPort[1];
Route[RD_ovld].RDSz[1] = strlen(hP[1]);
} else {
Route[RD_ovld].Host[1] = Route[RD_ovld].Host[0];
Route[RD_ovld].Port[1] = Route[RD_ovld].Port[0];
Route[RD_ovld].RDSz[1] = Route[RD_ovld].RDSz[0];
}
OD_Redir = true;
} else OD_Redir = false;

return 0;
}

/******************************************************************************/
/* x l o g */
/******************************************************************************/
Expand Down Expand Up @@ -1337,38 +1424,22 @@ int XrdXrootdProtocol::xred(XrdOucStream &Config)
{"trunc", RD_trunc}
};
static const int rHLen = 264;
char rHost[2][rHLen], *hP[2], *val, *pp;
char rHost[2][rHLen], *hP[2], *val;
int i, k, neg, numopts = sizeof(rdopts)/sizeof(struct rediropts);
int rPort[2], isQ = 0;

// Get the host and port
//
val = Config.GetWord();
if (!xred_php(val, hP, rPort)) return 1;

// Check if we have two hosts here
//
hP[0] = val;
if (!(pp = index(val, '%'))) hP[1] = 0;
else {hP[1] = pp+1; *pp = 0;}

// Verify corectness here
//
if (!(*val) || (hP[1] && !hP[1]))
{eDest.Emsg("Config", "malformed redirect host specification"); return 1;}

// Process the hosts
// Copy out he values as the target variable will be lost
//
for (i = 0; i < 2; i++)
{if (!(val = hP[i])) break;
if (!val || !val[0] || val[0] == ':')
{eDest.Emsg("Config", "redirect host not specified"); return 1;}
if (!(pp = rindex(val, ':')))
{eDest.Emsg("Config", "redirect port not specified"); return 1;}
if (!(rPort[i] = atoi(pp+1)))
{eDest.Emsg("Config", "redirect port is invalid"); return 1;}
*pp = '\0';
strlcpy(rHost[i], val, rHLen);
hP[i] = rHost[i];
{if (!hP[i]) rHost[i][0] = 0;
else {strlcpy(rHost[i], hP[i], rHLen);
hP[i] = rHost[i];
}
}

// Set all redirect target functions
Expand Down Expand Up @@ -1424,6 +1495,45 @@ int XrdXrootdProtocol::xred(XrdOucStream &Config)
return 0;
}

bool XrdXrootdProtocol::xred_php(char *val, char *hP[2], int rPort[2])
{
char *pp;

// Make sure we have a value
//
if (!val || !(*val))
{eDest.Emsg("config", "redirect option not specified"); return false;}

// Check if we have two hosts here
//
hP[0] = val;
if (!(pp = index(val, '%'))) hP[1] = 0;
else {hP[1] = pp+1; *pp = 0;}

// Verify corectness here
//
if (!(*val) || (hP[1] && !*hP[1]))
{eDest.Emsg("Config", "malformed redirect host specification");
return false;
}

// Process the hosts
//
for (int i = 0; i < 2; i++)
{if (!(val = hP[i])) break;
if (!val || !val[0] || val[0] == ':')
{eDest.Emsg("Config", "redirect host not specified"); return false;}
if (!(pp = rindex(val, ':')))
{eDest.Emsg("Config", "redirect port not specified"); return false;}
if (!(rPort[i] = atoi(pp+1)))
{eDest.Emsg("Config", "redirect port is invalid"); return false;}
*pp = '\0';
}

// All done
//
return true;
}

void XrdXrootdProtocol::xred_set(RD_func func, char *rHost[2], int rPort[2])
{
Expand Down
1 change: 1 addition & 0 deletions src/XrdXrootd/XrdXrootdMonData.hh
Expand Up @@ -132,6 +132,7 @@ const kXR_char XROOTD_MON_TRUNC = 0x0e;
const kXR_char XROOTD_MON_FORCED = 0x01;
const kXR_char XROOTD_MON_BOUNDP = 0x02;

const int XROOTD_MON_REDMASK = 0x00000ff;
const int XROOTD_MON_SRCMASK = 0x000000f;
const int XROOTD_MON_TRGMASK = 0x7fffff0;
const int XROOTD_MON_NEWSTID = 0x8000000;
Expand Down
3 changes: 3 additions & 0 deletions src/XrdXrootd/XrdXrootdProtocol.cc
Expand Up @@ -122,6 +122,9 @@ int XrdXrootdProtocol::PrepareLimit = -1;
bool XrdXrootdProtocol::LimitError = true;

struct XrdXrootdProtocol::RD_Table XrdXrootdProtocol::Route[RD_Num];
int XrdXrootdProtocol::OD_Stall = 33;
bool XrdXrootdProtocol::OD_Bypass= false;
bool XrdXrootdProtocol::OD_Redir = false;

/******************************************************************************/
/* P r o t o c o l M a n a g e m e n t S t a c k s */
Expand Down
9 changes: 7 additions & 2 deletions src/XrdXrootd/XrdXrootdProtocol.hh
Expand Up @@ -132,7 +132,7 @@ private:
//
enum RD_func {RD_chmod = 0, RD_chksum, RD_dirlist, RD_locate, RD_mkdir,
RD_mv, RD_prepare, RD_prepstg, RD_rm, RD_rmdir,
RD_stat, RD_trunc,
RD_stat, RD_trunc, RD_ovld,
RD_open1, RD_open2, RD_open3, RD_open4, RD_Num};

int do_Admin();
Expand Down Expand Up @@ -193,7 +193,7 @@ static int Config(const char *fn);
static int ConfigSecurity(XrdOucEnv &xEnv, const char *cfn);
int fsError(int rc, char opc, XrdOucErrInfo &myError,
const char *Path, char *Cgi);
int fsRedir(RD_func xfnc);
int fsOvrld(char opc, const char *Path, char *Cgi);
int fsRedirNoEnt(const char *eMsg, char *Cgi, int popt);
int getBuff(const int isRead, int Quantum);
int getData(const char *dtype, char *buff, int blen);
Expand All @@ -213,11 +213,13 @@ static int xexp(XrdOucStream &Config);
static int xexpdo(char *path, int popt=0);
static int xfsl(XrdOucStream &Config);
static int xfsL(XrdOucStream &Config, char *val, int lix);
static int xfso(XrdOucStream &Config);
static int xpidf(XrdOucStream &Config);
static int xprep(XrdOucStream &Config);
static int xlog(XrdOucStream &Config);
static int xmon(XrdOucStream &Config);
static int xred(XrdOucStream &Config);
static bool xred_php(char *val, char *hP[2], int rPort[2]);
static void xred_set(RD_func func, char *rHost[2], int rPort[2]);
static bool xred_xok(int func, char *rHost[2], int rPort[2]);
static int xsecl(XrdOucStream &Config);
Expand Down Expand Up @@ -284,6 +286,9 @@ static XrdOucReqID *PrepID;
static struct RD_Table {char *Host[2];
unsigned short Port[2];
short RDSz[2];} Route[RD_Num];
static int OD_Stall;
static bool OD_Bypass;
static bool OD_Redir;

// async configuration values
//
Expand Down

0 comments on commit 404954c

Please sign in to comment.