16 #include "XrdVersion.hh"
34 m_write_through(false),
36 m_allow_xrdpfc_command(false),
37 m_data_space(
"public"),
38 m_meta_space(
"public"),
42 m_fileUsageBaseline(-1),
43 m_fileUsageNominal(-1),
46 m_purgeColdFilesAge(-1),
47 m_purgeAgeBasedPeriod(10),
49 m_dirStatsInterval(1500),
50 m_dirStatsMaxDepth(-1),
51 m_dirStatsStoreDepth(0),
52 m_bufferSize(128*1024),
54 m_RamKeepStdBlocks(0),
57 m_prefetch_max_blocks(10),
58 m_hdfsbsize(128*1024*1024),
63 m_onlyIfCachedMinSize(1024*1024),
64 m_onlyIfCachedMinFrac(1.0)
68 bool Cache::cfg2bytes(
const std::string &str,
long long &store,
long long totalSpace,
const char *name)
71 snprintf(errStr, 1024,
"ConfigParameters() Error parsing parameter %s", name);
73 if (::isalpha(*(str.rbegin())))
84 double frac = strtod(str.c_str(), &eP);
85 if (errno || eP == str.c_str())
87 m_log.
Emsg(errStr, str.c_str());
91 store =
static_cast<long long>(totalSpace * frac + 0.5);
94 if (store < 0 || store > totalSpace)
96 snprintf(errStr, 1024,
"ConfigParameters() Error: parameter %s should be between 0 and total available disk space (%lld) - it is %lld (given as %s)",
97 name, totalSpace, store, str.c_str());
98 m_log.
Emsg(errStr,
"");
126 const char *val, *val2;
127 struct cschkopts {
const char *opname;
int opval;} csopts[] =
134 int i, numopts =
sizeof(csopts)/
sizeof(
struct cschkopts);
137 if (! (val =
Config.GetWord()))
138 {m_log.
Emsg(
"Config",
"cschk parameter not specified");
return false; }
142 if ((
isNo = strncmp(val,
"no", 2) == 0))
146 for (i = 0; i < numopts; i++)
148 if (!strcmp(val2, csopts[i].opname))
151 m_configuration.
m_cs_Chk &= ~csopts[i].opval;
152 else if (csopts[i].opval)
153 m_configuration.
m_cs_Chk |= csopts[i].opval;
155 m_configuration.
m_cs_Chk = csopts[i].opval;
161 if (strcmp(val,
"uvkeep"))
163 m_log.
Emsg(
"Config",
"invalid cschk option -", val);
166 if (!(val =
Config.GetWord()))
168 m_log.
Emsg(
"Config",
"cschk uvkeep value not specified");
171 if (!strcmp(val,
"lru"))
184 m_configuration.m_cs_ChkTLS = m_configuration.m_cs_Chk &
CSChk_TLS;
187 m_env->Put(
"psx.CSNet", m_configuration.is_cschk_net() ? (m_configuration.m_cs_ChkTLS ?
"2" :
"1") :
"0");
208 if (! (val =
Config.GetWord()) || ! val[0])
210 TRACE(
Info,
" Cache::Config() decisionlib not specified; always caching files");
220 Config.GetRest(params, 4096);
229 if (! ep) {myLib->
Unload(
true);
return false; }
234 TRACE(
Error,
"Config() decisionlib was not able to create a decision object");
240 m_decisionpoints.push_back(d);
259 if (! (val =
Config.GetWord()) || ! val[0])
261 TRACE(
Info,
" Cache::Config() purgelib not specified; will use LRU for purging files");
271 Config.GetRest(params, 4096);
280 if (! ep) {myLib->
Unload(
true);
return false; }
285 TRACE(
Error,
"Config() purgelib was not able to create a Purge Plugin object?");
305 static struct traceopts {
const char *opname;
int opval; } tropts[] =
315 int numopts =
sizeof(tropts)/
sizeof(
struct traceopts);
317 if (! (val =
Config.GetWord()))
318 {m_log.
Emsg(
"Config",
"trace option not specified");
return 1; }
320 for (
int i = 0; i < numopts; i++)
322 if (! strcmp(val, tropts[i].opname))
324 m_trace->
What = tropts[i].opval;
328 m_log.
Emsg(
"Config",
"invalid trace option -", val);
333 bool Cache::test_oss_basics_and_features()
335 static const char *epfx =
"test_oss_basics_and_features()";
337 const auto &conf = m_configuration;
341 auto check_space = [&](
const char *space,
bool &has_xattr)
343 std::string fname(
"__prerun_test_pfc_");
346 env.
Put(
"oss.cgroup", space);
350 m_log.
Emsg(epfx,
"Can not create a file on space", space);
354 res = oss_file->
Open(fname.c_str(), O_RDWR, 0600, env);
356 m_log.
Emsg(epfx,
"Can not open a file on space", space);
359 res = oss_file->
Write(fname.data(), 0, fname.length());
360 if (res != (
int) fname.length()) {
361 m_log.
Emsg(epfx,
"Can not write into a file on space", space);
366 long long fsize = fname.length();
369 m_log.
Emsg(epfx,
"Can not write xattr to a file on space", space);
377 m_oss->
Lfn2Pfn(fname.c_str(), pfn, 4096);
380 if (res !=
sizeof(
long long) || fsize != (
long long) fname.length())
382 m_log.
Emsg(epfx,
"Can not read xattr from a file on space", space);
387 res = m_oss->
Unlink(fname.c_str());
389 m_log.
Emsg(epfx,
"Can not unlink a file on space", space);
397 aOK &= check_space(conf.m_data_space.c_str(), m_dataXattr);
398 aOK &= check_space(conf.m_meta_space.c_str(), m_metaXattr);
412 const char *theINS = getenv(
"XRDINSTANCE");
413 m_isClient = (theINS != 0 && strncmp(
"*client ", theINS, 8) == 0);
421 if (! config_filename || ! *config_filename)
423 TRACE(
Error,
"Config() configuration file not specified.");
428 if ( (fd =
open(config_filename, O_RDONLY, 0)) < 0)
430 TRACE(
Error,
"Config() can't open configuration file " << config_filename);
435 static const char *cvec[] = {
"*** pfc plugin config:", 0 };
441 if (! ofsCfg)
return false;
457 bool retval =
true, aOK =
true;
459 while ((var =
Config.GetMyFirstWord()))
461 if (! strcmp(var,
"pfc.osslib"))
465 else if (! strcmp(var,
"pfc.cschk"))
469 else if (! strcmp(var,
"pfc.decisionlib"))
473 else if (! strcmp(var,
"pfc.purgelib"))
477 else if (! strcmp(var,
"pfc.trace"))
481 else if (! strcmp(var,
"pfc.allow_xrdpfc_command"))
485 else if (! strncmp(var,
"pfc.", 4))
487 retval = ConfigParameters(std::string(var+4),
Config, tmpc);
500 myEnv.
Put(
"oss.runmode",
"pfc");
504 if (snprintf(csi_conf, 128,
"space=%s nofill", m_configuration.
m_meta_space.c_str()) < 128)
508 TRACE(
Error,
"Config() buffer too small for libXrdOssCsi params.");
518 TRACE(
Error,
"Config() Unable to create an OSS object");
523 aOK &= test_oss_basics_and_features();
531 m_log.
Emsg(
"ConfigParameters()",
"error obtaining stat info for meta space ", m_configuration.
m_meta_space.c_str());
536 m_log.
Emsg(
"ConfigParameters()",
"available data space is less than 10 MB (can be due to a mistake in oss.localroot directive) for space ",
542 m_log.
Emsg(
"ConfigParameters()",
"error obtaining stat info for data space ", m_configuration.
m_data_space.c_str());
545 if (sP.
Total < 10ll << 20)
547 m_log.
Emsg(
"ConfigParameters()",
"available data space is less than 10 MB (can be due to a mistake in oss.localroot directive) for space ",
558 m_log.
Emsg(
"ConfigParameters()",
"pfc.diskusage should have lowWatermark < highWatermark.");
574 m_log.
Emsg(
"ConfigParameters()",
"pfc.diskusage files should have baseline < nominal < max.");
581 m_log.
Emsg(
"ConfigParameters()",
"pfc.diskusage files values must be below lowWatermark");
621 m_log.
Emsg(
"ConfigParameters()",
"Unknown value for pfc.writemode (valid values are `writethrough` or `off`): %s",
630 m_configuration.
m_RamAbsAvailable = m_isClient ? 256ll * 1024 * 1024 : 1024ll * 1024 * 1024;
632 snprintf(buff,
sizeof(buff),
"RAM usage pfc.ram is not specified. Default value %s is used.", m_isClient ?
"256m" :
"1g");
633 m_log.
Say(
"Config info: ", buff);
639 char* cenv = getenv(
"XRDDEBUG");
640 if (cenv && ! strcmp(cenv,
"1") && m_trace->
What < 4) m_trace->
What = 4;
646 const char *csc[] = {
"off",
"cache nonet",
"nocache net notls",
650 "off",
"cache nonet",
"nocache net tls",
653 char buff[8192], uvk[32];
657 sprintf(uvk,
"%lld", (
long long) m_configuration.
m_cs_UVKeep);
659 loff = snprintf(buff,
sizeof(buff),
"Config effective %s pfc configuration:\n"
660 " pfc.cschk %s uvkeep %s\n"
661 " pfc.blocksize %lld\n"
664 " pfc.writequeue %d %d\n"
665 " # Total available disk: %lld\n"
666 " pfc.diskusage %lld %lld files %lld %lld %lld purgeinterval %d purgecoldfiles %d\n"
667 " pfc.spaces %s %s\n"
670 " pfc.acchistorysize %d\n"
671 " pfc.onlyIfCachedMinBytes %lld\n"
672 " pfc.onlyIfCachedMinFrac %.2f\n",
674 csc[
int(m_configuration.
m_cs_Chk)], uvk,
693 loff += snprintf(buff + loff,
sizeof(buff) - loff,
694 " pfc.dirstats interval %d maxdepth %d ((internal: store_depth %d, size_of_dirlist %d, size_of_globlist %d))\n",
697 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" dirlist:\n");
699 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" %s\n", i->c_str());
700 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" globlist:\n");
702 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" %s/*\n", i->c_str());
707 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" pfc.hdfsmode hdfsbsize %lld\n", m_configuration.
m_hdfsbsize);
709 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" pfc.writemode %s\n", m_configuration.
m_write_through ?
"writethrough" :
"off");
719 loff += snprintf(buff + loff,
sizeof(buff) - loff,
" pfc.user %s\n", m_configuration.
m_username.c_str());
724 m_env->
Put(
"XRDPFC.SEGSIZE", std::to_string(m_configuration.
m_bufferSize).c_str());
733 m_log.
Say(
" pfc g-stream has", m_gstream ?
"" :
" NOT",
" been configured via xrootd.monitor directive\n");
742 m_log.
Say(
"=====> Proxy file cache configuration parsing ", aOK ?
"completed" :
"failed");
744 if (ofsCfg)
delete ofsCfg;
748 #ifdef XRDPFC_CKSUM_TEST
754 Info::TestCksumStuff();
768 struct ConfWordGetter
773 ConfWordGetter(
XrdOucStream& c) : m_config(c), m_last_word((char*)1) {}
775 const char* GetWord() {
if (HasLast()) m_last_word = m_config.
GetWord();
return HasLast() ? m_last_word :
""; }
776 bool HasLast() {
return (m_last_word != 0); }
779 ConfWordGetter cwg(config);
782 if ( part ==
"user" )
785 if ( ! cwg.HasLast())
787 m_log.
Emsg(
"Config",
"Error: pfc.user requires a parameter.");
791 else if ( part ==
"diskusage" )
798 m_log.
Emsg(
"Config",
"Error: pfc.diskusage parameter requires at least two arguments.");
803 while ((p = cwg.GetWord()) && cwg.HasLast())
805 if (strcmp(p,
"files") == 0)
811 if ( ! cwg.HasLast())
813 m_log.
Emsg(
"Config",
"Error: pfc.diskusage files directive requires three arguments.");
817 else if (strcmp(p,
"sleep") == 0 || strcmp(p,
"purgeinterval") == 0)
819 if (strcmp(p,
"sleep") == 0) m_log.
Emsg(
"Config",
"warning sleep directive is deprecated in pfc.diskusage. Please use purgeinterval instead.");
826 else if (strcmp(p,
"purgecoldfiles") == 0)
839 m_log.
Emsg(
"Config",
"Error: diskusage stanza contains unknown directive", p);
843 else if ( part ==
"acchistorysize" )
850 else if ( part ==
"dirstats" )
853 while ((p = cwg.GetWord()) && cwg.HasLast())
855 if (strcmp(p,
"interval") == 0)
861 int validIntervals[] = {60, 300, 600, 900, 1800, 3600};
862 int size =
sizeof(validIntervals) /
sizeof(
int);
865 for (
int i = 0; i < size; i++) {
870 vvl += std::to_string(validIntervals[i]);
871 if ((i+1) != size) vvl +=
", ";
875 m_log.
Emsg(
"Config",
"Error: Dirstat interval is not valid. Possible interval values are ", vvl.c_str());
880 else if (strcmp(p,
"maxdepth") == 0)
888 else if (strcmp(p,
"dir") == 0)
891 if (p && p[0] ==
'/')
895 char d[1024]; d[0] = 0;
903 if (*(pd - 1) ==
'/')
915 if (*pd ==
'/' && pd != d) *pd = 0;
918 if (ld >= 2 && d[ld-1] ==
'*' && d[ld-2] ==
'/')
923 printf(
"Glob %s -> %s -- depth = %d\n", p, d, depth);
928 printf(
"Dir %s -> %s -- depth = %d\n", p, d, depth);
935 m_log.
Emsg(
"Config",
"Error: dirstats dir parameter requires a directory argument starting with a '/'.");
941 m_log.
Emsg(
"Config",
"Error: dirstats stanza contains unknown directive '", p,
"'");
946 else if ( part ==
"blocksize" )
948 long long minBSize = 4 * 1024;
949 long long maxBSize = 512 * 1024 * 1024;
958 m_log.
Emsg(
"Config",
"pfc.blocksize must be a multiple of 4 kB. Rounded up.");
961 else if ( part ==
"prefetch" || part ==
"nramprefetch" )
963 if (part ==
"nramprefetch")
965 m_log.
Emsg(
"Config",
"pfc.nramprefetch is deprecated, please use pfc.prefetch instead. Replacing the directive internally.");
974 else if ( part ==
"nramread" )
976 m_log.
Emsg(
"Config",
"pfc.nramread is deprecated, please use pfc.ram instead. Ignoring this directive.");
979 else if ( part ==
"ram" )
981 long long minRAM = m_isClient ? 256 * 1024 * 1024 : 1024 * 1024 * 1024;
982 long long maxRAM = 256 * minRAM;
988 else if ( part ==
"writequeue")
999 else if ( part ==
"spaces" )
1003 if ( ! cwg.HasLast())
1005 m_log.
Emsg(
"Config",
"spacenames requires two parameters: <data-space> <metadata-space>.");
1009 else if ( part ==
"hdfsmode" )
1011 m_log.
Emsg(
"Config",
"pfc.hdfsmode is currently unsupported.");
1016 const char* params = cwg.GetWord();
1019 if (! strncmp(
"hdfsbsize", params, 9))
1021 long long minBlSize = 32 * 1024;
1022 long long maxBlSize = 128 * 1024 * 1024;
1023 if (
XrdOuca2x::a2sz(m_log,
"Error getting file fragment size", cwg.GetWord(), &m_configuration.
m_hdfsbsize, minBlSize, maxBlSize))
1030 m_log.
Emsg(
"Config",
"Error setting the fragment size parameter name");
1035 else if ( part ==
"writemode" )
1038 if ( ! cwg.HasLast())
1040 m_log.
Emsg(
"Config",
"Error: pfc.writemode requires a parameter.");
1044 else if ( part ==
"flush" )
1047 if ( ! cwg.HasLast())
1049 m_log.
Emsg(
"Config",
"Error: pfc.flush requires a parameter.");
1053 else if ( part ==
"onlyifcached" )
1056 while ((p = cwg.GetWord()) && cwg.HasLast())
1058 if (strcmp(p,
"minsize") == 0)
1060 std::string minBytes = cwg.GetWord();
1061 long long minBytesTop = 1024 * 1024 * 1024;
1062 if (::isalpha(*(minBytes.rbegin())))
1077 if (strcmp(p,
"minfrac") == 0)
1079 std::string minFrac = cwg.GetWord();
1082 double frac = strtod(minFrac.c_str(), &eP);
1083 if (errno || eP == minFrac.c_str())
1085 m_log.
Emsg(
"Config",
"Error setting fraction for only-if-cached directive");
1092 m_log.
Emsg(
"Config",
"Error: onlyifcached stanza contains unknown directive", p);
1098 m_log.
Emsg(
"ConfigParameters() unmatched pfc parameter", part.c_str());
XrdSysXAttr * XrdSysXAttrActive
XrdVERSIONINFO(XrdOucGetCache, XrdPfc)
XrdOucCache * XrdOucGetCache(XrdSysLogger *logger, const char *config_filename, const char *parameters, XrdOucEnv *env)
int open(const char *path, int oflag,...)
int isNo(int dflt, const char *Msg1, const char *Msg2, const char *Msg3)
bool Plugin(XrdAccAuthorize *&piP)
Get Authorization plugin.
static XrdOfsConfigPI * New(const char *cfn, XrdOucStream *cfgP, XrdSysError *errP, XrdVersionInfo *verP=0, XrdSfsFileSystem *sfsP=0)
bool Load(int what, XrdOucEnv *envP=0)
bool Push(TheLib what, const char *plugP, const char *parmP=0)
virtual int Close(long long *retsz=0)=0
virtual int Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env)
virtual ssize_t Write(const void *buffer, off_t offset, size_t size)
virtual int Create(const char *tid, const char *path, mode_t mode, XrdOucEnv &env, int opts=0)=0
virtual int Lfn2Pfn(const char *Path, char *buff, int blen)
virtual int StatVS(XrdOssVSInfo *vsP, const char *sname=0, int updt=0)
virtual XrdOssDF * newFile(const char *tident)=0
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
static int Export(const char *Var, const char *Val)
void * GetPtr(const char *varname)
void Put(const char *varname, const char *value)
void * Resolve(const char *symbl, int mcnt=1)
void Unload(bool dodel=false)
char * GetWord(int lowcase=0)
static int UserName(uid_t uID, char *uName, int uNsz)
static int a2i(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
static int a2sz(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
static int a2ll(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
bool Config(const char *config_filename, const char *parameters)
Parse configuration file.
Base class for selecting which files should be cached.
virtual bool ConfigDecision(const char *params)
Status of cached file. Can be read from and written into a binary file.
static size_t s_maxNumAccess
Base class for reguesting directory space to obtain.
virtual bool ConfigPurgePin(const char *params)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
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)
virtual int Get(const char *Aname, void *Aval, int Avsz, const char *Path, int fd=-1)=0
virtual int Set(const char *Aname, const void *Aval, int Avsz, const char *Path, int fd=-1, int isNew=0)=0
const char * trace_what_strings[]
long long m_hdfsbsize
used with m_hdfsmode, default 128MB
long long m_RamAbsAvailable
available from configuration
long long m_flushCnt
nuber of unsynced blcoks on disk before flush is called
int m_accHistorySize
max number of entries in access history part of cinfo file
int m_wqueue_threads
number of threads writing blocks to disk
bool m_write_through
flag indicating write-through mode is enabled
long long m_diskTotalSpace
total disk space on configured partition or oss space
long long m_fileUsageMax
cache purge - files usage maximum
long long m_fileUsageBaseline
cache purge - files usage baseline
int m_dirStatsStoreDepth
depth to which statistics should be collected
bool m_allow_xrdpfc_command
flag for enabling access to /xrdpfc-command/ functionality.
long long m_diskUsageHWM
cache purge - disk usage high water mark
bool is_cschk_cache() const
std::set< std::string > m_dirStatsDirGlobs
directory globs for which stat reporting was requested
int m_prefetch_max_blocks
maximum number of blocks to prefetch per file
bool m_cs_ChkTLS
Allow TLS.
long long m_fileUsageNominal
cache purge - files usage nominal
int m_cs_Chk
Checksum check.
int m_purgeAgeBasedPeriod
peform cold file / uvkeep purge every this many purge cycles
bool m_hdfsmode
flag for enabling block-level operation
int m_purgeColdFilesAge
purge files older than this age
std::string m_data_space
oss space for data files
std::set< std::string > m_dirStatsDirs
directories for which stat reporting was requested
long long m_diskUsageLWM
cache purge - disk usage low water mark
int m_RamKeepStdBlocks
number of standard-sized blocks kept after release
long long m_bufferSize
prefetch buffer size, default 1MB
int m_dirStatsInterval
time between resource monitor statistics dump in seconds
std::string m_meta_space
oss space for metadata files (cinfo)
int m_wqueue_blocks
maximum number of blocks written per write-queue loop
std::string m_username
username passed to oss plugin
bool is_cschk_net() const
double m_onlyIfCachedMinFrac
minimum fraction of downloaded file, used by only-if-cached CGI option
time_t m_cs_UVKeep
unverified checksum cache keep
int m_dirStatsMaxDepth
maximum depth for statistics write out
int m_purgeInterval
sleep interval between cache purges
long long m_onlyIfCachedMinSize
minumum size of downloaded file, used by only-if-cached CGI option
bool is_dir_stat_reporting_on() const
std::string m_writemodeRaw
std::string m_diskUsageLWM
std::string m_diskUsageHWM
std::string m_fileUsageBaseline
std::string m_fileUsageNominal
std::string m_fileUsageMax