#include "TDataSetManager.h"
#include "Riostream.h"
#include "TEnv.h"
#include "TError.h"
#include "TFile.h"
#include "TFileCollection.h"
#include "TFileInfo.h"
#include "TFileStager.h"
#include "TMD5.h"
#include "THashList.h"
#include "TKey.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TParameter.h"
#include "TPRegexp.h"
#include "TRegexp.h"
#include "TSystem.h"
#include "TTree.h"
#include "TUrl.h"
#include "TVirtualMonitoring.h"
#define DSM_ONE_GB (1073741824)
TString TDataSetManager::fgCommonDataSetTag = "COMMON";
TList *TDataSetManager::fgDataSetSrvMaps = 0;
ClassImp(TDataSetManager)
TDataSetManager::TDataSetManager(const char *group, const char *user,
const char *options)
: fGroup(group),
fUser(user), fCommonUser(), fCommonGroup(),
fGroupQuota(), fGroupUsed(),
fUserUsed(), fNTouchedFiles(0), fNOpenedFiles(0),
fNDisappearedFiles(0), fMTimeGroupConfig(-1)
{
if (fGroup.IsNull())
fGroup = "default";
if (fUser.IsNull()) {
fUser = "--nouser--";
UserGroup_t *pw = gSystem->GetUserInfo();
if (pw) {
fUser = pw->fUser;
delete pw;
}
}
fGroupQuota.SetOwner();
fGroupUsed.SetOwner();
fUserUsed.SetOwner();
fCommonUser = "COMMON";
fCommonGroup = "COMMON";
fNTouchedFiles = -1;
fNOpenedFiles = -1;
fNDisappearedFiles = -1;
fMTimeGroupConfig = -1;
fAvgFileSize = 50000000;
ParseInitOpts(options);
if (!fUser.IsNull() && !fGroup.IsNull()) {
if (!TestBit(TDataSetManager::kIsSandbox))
fBase.SetUri(TString(Form("/%s/%s/", fGroup.Data(), fUser.Data())));
}
TString srvmaps(gEnv->GetValue("DataSet.SrvMaps",""));
TString srvmapsenv(gSystem->Getenv("DATASETSRVMAPS"));
if (!(srvmapsenv.IsNull())) {
if (srvmapsenv.BeginsWith("+")) {
if (!(srvmaps.IsNull())) srvmaps += ",";
srvmaps += srvmapsenv(1,srvmapsenv.Length());
} else {
srvmaps = srvmapsenv;
}
}
if (!(srvmaps.IsNull()) && !(fgDataSetSrvMaps = ParseDataSetSrvMaps(srvmaps)))
Warning("TDataSetManager", "problems parsing DataSet.SrvMaps input info (%s)"
" - ignoring", srvmaps.Data());
ReadGroupConfig(gEnv->GetValue("Proof.GroupFile", ""));
}
TDataSetManager::~TDataSetManager()
{
fGroupQuota.DeleteAll();
fGroupUsed.DeleteAll();
fUserUsed.DeleteAll();
}
void TDataSetManager::ParseInitOpts(const char *opts)
{
ResetBit(TDataSetManager::kCheckQuota);
SetBit(TDataSetManager::kAllowRegister);
SetBit(TDataSetManager::kAllowVerify);
SetBit(TDataSetManager::kTrustInfo);
ResetBit(TDataSetManager::kIsSandbox);
ResetBit(TDataSetManager::kUseCache);
ResetBit(TDataSetManager::kDoNotUseCache);
if (opts && strlen(opts) > 0) {
TString opt(opts);
Int_t ip = opt.Index("opt:");
if (ip != kNPOS) opt.Remove(0, ip + 4);
ip = opt.Index(" ");
if (ip != kNPOS) opt.Remove(ip);
if (opt.Contains("Cq:") && !opt.Contains("-Cq:"))
SetBit(TDataSetManager::kCheckQuota);
if (opt.Contains("-Ar:"))
ResetBit(TDataSetManager::kAllowRegister);
if (opt.Contains("-Av:"))
ResetBit(TDataSetManager::kAllowVerify);
if (opt.Contains("-Ti:"))
ResetBit(TDataSetManager::kTrustInfo);
if (opt.Contains("Sb:") && !opt.Contains("-Sb:"))
SetBit(TDataSetManager::kIsSandbox);
if (opt.Contains("Ca:"))
SetBit(TDataSetManager::kUseCache);
if (opt.Contains("-Ca:"))
SetBit(TDataSetManager::kDoNotUseCache);
}
if (TestBit(TDataSetManager::kAllowVerify)) {
SetBit(TDataSetManager::kAllowRegister);
}
if (TestBit(TDataSetManager::kUseCache) && TestBit(TDataSetManager::kDoNotUseCache))
ResetBit(TDataSetManager::kDoNotUseCache);
}
Bool_t TDataSetManager::ReadGroupConfig(const char *cf)
{
FileStat_t st;
if (!cf || (strlen(cf) <= 0) || !strcmp(cf, fGroupConfigFile.Data())) {
if (fGroupConfigFile.IsNull()) {
if (gDebug > 0)
Info("ReadGroupConfig", "path to config file undefined - nothing to do");
return kFALSE;
}
if (gSystem->GetPathInfo(fGroupConfigFile, st)) {
Error("ReadGroupConfig", "could not stat %s", fGroupConfigFile.Data());
return kFALSE;
}
if (st.fMtime <= fMTimeGroupConfig) {
if (gDebug > 0)
Info("ReadGroupConfig","file has not changed - do nothing");
return kTRUE;
}
}
if (cf && (strlen(cf) > 0)) {
if (gSystem->GetPathInfo(cf, st)) {
Error("ReadGroupConfig", "could not stat %s", cf);
return kFALSE;
}
if (gSystem->AccessPathName(cf, kReadPermission)) {
Error("ReadGroupConfig", "cannot read %s", cf);
return kFALSE;
}
fGroupConfigFile = cf;
fMTimeGroupConfig = st.fMtime;
}
if (gDebug > 0)
Info("ReadGroupConfig","reading group config from %s", cf);
ifstream in;
in.open(cf);
if (!in.is_open()) {
Error("ReadGroupConfig", "could not open config file %s", cf);
return kFALSE;
}
TString tmpCommonUser;
TString line;
while (in.good()) {
line.ReadLine(in);
if (line[0] == '#') continue;
Ssiz_t from = 0;
TString key;
if (!line.Tokenize(key, from, " "))
continue;
if (key == "property") {
TString grp;
if (!line.Tokenize(grp, from, " ")) {
if (gDebug > 0)
Info("ReadGroupConfig","incomplete line: '%s'", line.Data());
continue;
}
TString type;
if (!line.Tokenize(type, from, " "))
continue;
if (type == "diskquota") {
TString sdq;
if (!line.Tokenize(sdq, from, " "))
continue;
if (sdq.IsDigit()) sdq += "G";
Long64_t quota = ToBytes(sdq);
if (quota > -1) {
fGroupQuota.Add(new TObjString(grp),
new TParameter<Long64_t> ("group quota", quota));
} else {
Warning("ReadGroupConfig",
"problems parsing string: wrong or unsupported suffix? %s",
sdq.Data());
}
} else if (type == "commonuser") {
TString comusr;
if (!line.Tokenize(comusr, from, " "))
continue;
}
} else if (key == "dataset") {
TString type;
if (!line.Tokenize(type, from, " ")) {
if (gDebug > 0)
Info("ReadGroupConfig","incomplete line: '%s'", line.Data());
continue;
}
if (type == "commonuser") {
TString comusr;
if (!line.Tokenize(comusr, from, " "))
continue;
fCommonUser = comusr;
} else if (type == "commongroup") {
TString comgrp;
if (!line.Tokenize(comgrp, from, " "))
continue;
fCommonGroup = comgrp;
} else if (type == "diskquota") {
TString on;
if (!line.Tokenize(on, from, " "))
continue;
if (on == "on") {
SetBit(TDataSetManager::kCheckQuota);
} else if (on == "off") {
ResetBit(TDataSetManager::kCheckQuota);
}
}
} else if (key == "averagefilesize") {
TString avgsize;
if (!line.Tokenize(avgsize, from, " ")) {
if (gDebug > 0)
Info("ReadGroupConfig","incomplete line: '%s'", line.Data());
continue;
}
Long64_t avgsz = ToBytes(avgsize);
if (avgsz > -1) {
fAvgFileSize = avgsz;
} else {
Warning("ReadGroupConfig",
"problems parsing string: wrong or unsupported suffix? %s",
avgsize.Data());
}
} else if (key == "include") {
TString subfn;
if (!line.Tokenize(subfn, from, " ")) {
if (gDebug > 0)
Info("ReadGroupConfig","incomplete line: '%s'", line.Data());
continue;
}
if (gSystem->AccessPathName(subfn, kReadPermission)) {
Error("ReadGroupConfig", "request to parse file '%s' which is not readable",
subfn.Data());
continue;
}
if (!ReadGroupConfig(subfn))
Error("ReadGroupConfig", "problems parsing include file '%s'", subfn.Data());
}
}
in.close();
return kTRUE;
}
Long64_t TDataSetManager::ToBytes(const char *size)
{
Long64_t lsize = -1;
if (!size || strlen(size) <= 0) return lsize;
TString s(size);
Long64_t fact = 1;
if (!s.IsDigit()) {
const char *unit[5] = { "k", "M", "G", "T", "P"};
fact = 1024;
Int_t jj = 0;
while (jj <= 4) {
if (s.EndsWith(unit[jj], TString::kIgnoreCase)) {
s.Remove(s.Length()-1);
break;
}
fact *= 1024;
jj++;
}
}
if (s.IsDigit())
lsize = s.Atoi() * fact;
return lsize;
}
TFileCollection *TDataSetManager::GetDataSet(const char *, const char *)
{
AbstractMethod("GetDataSet");
return (TFileCollection *)0;
}
Bool_t TDataSetManager::RemoveDataSet(const char *)
{
AbstractMethod("RemoveDataSet");
return kFALSE;
}
Bool_t TDataSetManager::ExistsDataSet(const char *)
{
AbstractMethod("ExistsDataSet");
return kFALSE;
}
TMap *TDataSetManager::GetDataSets(const char *, UInt_t)
{
AbstractMethod("GetDataSets");
return (TMap *)0;
}
Int_t TDataSetManager::ScanDataSet(const char *uri, const char *opts)
{
UInt_t o = 0;
if (opts) {
if (strstr(opts, "allfiles:") || strchr(opts, 'A'))
o |= kAllFiles;
else if (strstr(opts, "staged:") || strchr(opts, 'D'))
o |= kStagedFiles;
if (strstr(opts, "open:") || strchr(opts, 'O'))
o |= kReopen;
if (strstr(opts, "touch:") || strchr(opts, 'T'))
o |= kTouch;
if (strstr(opts, "nostagedcheck:") || strchr(opts, 'I'))
o |= kNoStagedCheck;
if (strstr(opts, "noaction:") || strchr(opts, 'N'))
o |= kNoAction;
if (strstr(opts, "locateonly:") || strchr(opts, 'L'))
o |= kLocateOnly;
if (strstr(opts, "stageonly:") || strchr(opts, 'S'))
o |= kStageOnly;
if (strstr(opts, "verbose:") || strchr(opts, 'V'))
o |= kDebug;
} else {
o = kReopen | kDebug;
}
return ScanDataSet(uri, o);
}
Int_t TDataSetManager::ScanDataSet(const char *, UInt_t)
{
AbstractMethod("ScanDataSet");
return -1;
}
void TDataSetManager::GetQuota(const char *group, const char *user,
const char *dsName, TFileCollection *dataset)
{
if (gDebug > 0)
Info("GetQuota", "processing dataset %s %s %s", group, user, dsName);
if (dataset->GetTotalSize() > 0) {
TParameter<Long64_t> *size =
dynamic_cast<TParameter<Long64_t>*> (fGroupUsed.GetValue(group));
if (!size) {
size = new TParameter<Long64_t> ("group used", 0);
fGroupUsed.Add(new TObjString(group), size);
}
size->SetVal(size->GetVal() + dataset->GetTotalSize());
TMap *userMap = dynamic_cast<TMap*> (fUserUsed.GetValue(group));
if (!userMap) {
userMap = new TMap;
fUserUsed.Add(new TObjString(group), userMap);
}
size = dynamic_cast<TParameter<Long64_t>*> (userMap->GetValue(user));
if (!size) {
size = new TParameter<Long64_t> ("user used", 0);
userMap->Add(new TObjString(user), size);
}
size->SetVal(size->GetVal() + dataset->GetTotalSize());
}
}
void TDataSetManager::ShowQuota(const char *opt)
{
UpdateUsedSpace();
TMap *groupQuotaMap = GetGroupQuotaMap();
TMap *userUsedMap = GetUserUsedMap();
if (!groupQuotaMap || !userUsedMap)
return;
Bool_t noInfo = kTRUE;
TIter iter(groupQuotaMap);
TObjString *group = 0;
while ((group = dynamic_cast<TObjString*> (iter.Next()))) {
noInfo = kFALSE;
Long64_t groupQuota = GetGroupQuota(group->String());
Long64_t groupUsed = GetGroupUsed(group->String());
Printf(" +++ Group %s uses %.1f GB out of %.1f GB", group->String().Data(),
(Float_t) groupUsed / DSM_ONE_GB,
(Float_t) groupQuota / DSM_ONE_GB);
if (opt && !TString(opt).Contains("U", TString::kIgnoreCase))
continue;
TMap *userMap = dynamic_cast<TMap*> (userUsedMap->GetValue(group->String()));
if (!userMap)
continue;
TIter iter2(userMap);
TObjString *user = 0;
while ((user = dynamic_cast<TObjString*> (iter2.Next()))) {
TParameter<Long64_t> *size2 =
dynamic_cast<TParameter<Long64_t>*> (userMap->GetValue(user->String().Data()));
if (!size2)
continue;
Printf(" +++ User %s uses %.1f GB", user->String().Data(),
(Float_t) size2->GetVal() / DSM_ONE_GB);
}
Printf("------------------------------------------------------");
}
if (noInfo) {
Printf(" +++ Quota check enabled but no quota info available +++ ");
}
}
void TDataSetManager::PrintUsedSpace()
{
Info("PrintUsedSpace", "listing used space");
TIter iter(&fUserUsed);
TObjString *group = 0;
while ((group = dynamic_cast<TObjString*> (iter.Next()))) {
TMap *userMap = dynamic_cast<TMap*> (fUserUsed.GetValue(group->String()));
TParameter<Long64_t> *size =
dynamic_cast<TParameter<Long64_t>*> (fGroupUsed.GetValue(group->String()));
if (userMap && size) {
Printf("Group %s: %lld B = %.2f GB", group->String().Data(), size->GetVal(),
(Float_t) size->GetVal() / DSM_ONE_GB);
TIter iter2(userMap);
TObjString *user = 0;
while ((user = dynamic_cast<TObjString*> (iter2.Next()))) {
TParameter<Long64_t> *size2 =
dynamic_cast<TParameter<Long64_t>*> (userMap->GetValue(user->String().Data()));
if (size2)
Printf(" User %s: %lld B = %.2f GB", user->String().Data(), size2->GetVal(),
(Float_t) size2->GetVal() / DSM_ONE_GB);
}
Printf("------------------------------------------------------");
}
}
}
void TDataSetManager::MonitorUsedSpace(TVirtualMonitoringWriter *monitoring)
{
Info("MonitorUsedSpace", "sending used space to monitoring server");
TIter iter(&fUserUsed);
TObjString *group = 0;
while ((group = dynamic_cast<TObjString*> (iter.Next()))) {
TMap *userMap = dynamic_cast<TMap*> (fUserUsed.GetValue(group->String()));
TParameter<Long64_t> *size =
dynamic_cast<TParameter<Long64_t>*> (fGroupUsed.GetValue(group->String()));
if (!userMap || !size)
continue;
TList *list = new TList;
list->SetOwner();
list->Add(new TParameter<Long64_t>("_TOTAL_", size->GetVal()));
Long64_t groupQuota = GetGroupQuota(group->String());
if (groupQuota != -1)
list->Add(new TParameter<Long64_t>("_QUOTA_", groupQuota));
TIter iter2(userMap);
TObjString *user = 0;
while ((user = dynamic_cast<TObjString*> (iter2.Next()))) {
TParameter<Long64_t> *size2 =
dynamic_cast<TParameter<Long64_t>*> (userMap->GetValue(user->String().Data()));
if (!size2)
continue;
list->Add(new TParameter<Long64_t>(user->String().Data(), size2->GetVal()));
}
monitoring->SendParameters(list, group->String());
delete list;
}
}
Long64_t TDataSetManager::GetGroupUsed(const char *group)
{
if (fgCommonDataSetTag == group)
group = fCommonGroup;
TParameter<Long64_t> *size =
dynamic_cast<TParameter<Long64_t>*> (fGroupUsed.GetValue(group));
if (!size) {
if (gDebug > 0)
Info("GetGroupUsed", "group %s not found", group);
return 0;
}
return size->GetVal();
}
Long64_t TDataSetManager::GetGroupQuota(const char *group)
{
if (fgCommonDataSetTag == group)
group = fCommonGroup;
TParameter<Long64_t> *value =
dynamic_cast<TParameter<Long64_t>*> (fGroupQuota.GetValue(group));
if (!value) {
if (gDebug > 0)
Info("GetGroupQuota", "group %s not found", group);
return 0;
}
return value->GetVal();
}
void TDataSetManager::UpdateUsedSpace()
{
AbstractMethod("UpdateUsedSpace");
}
Int_t TDataSetManager::RegisterDataSet(const char *,
TFileCollection *, const char *)
{
AbstractMethod("RegisterDataSet");
return -1;
}
Int_t TDataSetManager::NotifyUpdate(const char * ,
const char * ,
const char * ,
Long_t ,
const char * )
{
AbstractMethod("NotifyUpdate");
return -1;
}
Int_t TDataSetManager::ClearCache(const char * )
{
AbstractMethod("ClearCache");
return -1;
}
Int_t TDataSetManager::ShowCache(const char * )
{
AbstractMethod("ShowCache");
return -1;
}
TString TDataSetManager::CreateUri(const char *dsGroup, const char *dsUser,
const char *dsName, const char *dsObjPath)
{
TString uri;
if (dsGroup && strlen(dsGroup) > 0) {
if (dsUser && strlen(dsUser) > 0) {
uri += Form("/%s/%s/", dsGroup, dsUser);
} else {
uri += Form("/%s/*/", dsGroup);
}
} else if (dsUser && strlen(dsUser) > 0) {
uri += Form("%s/", dsUser);
}
if (dsName && strlen(dsName) > 0)
uri += dsName;
if (dsObjPath && strlen(dsObjPath) > 0)
uri += Form("#%s", dsObjPath);
return uri;
}
Bool_t TDataSetManager::ParseUri(const char *uri,
TString *dsGroup, TString *dsUser,
TString *dsName, TString *dsTree,
Bool_t onlyCurrent, Bool_t wildcards)
{
TString uristr(uri);
Int_t pc = 0;
if (wildcards && uristr.Length() > 0) {
pc = uristr.CountChar('/');
Bool_t endsl = uristr.EndsWith("/") ? kTRUE : kFALSE;
Bool_t beginsl = uristr.BeginsWith("/") ? kTRUE : kFALSE;
if (beginsl) {
if (pc == 1) uristr += "/*/";
if (pc == 2 && endsl) uristr += "*/";
if (pc == 2 && !endsl) uristr += "/";
}
}
TUri resolved = TUri::Transform(uristr, fBase);
if (resolved.HasQuery())
Info ("ParseUri", "URI query part <%s> ignored", resolved.GetQuery().Data());
TString path(resolved.GetPath());
if ((pc = path.CountChar('/')) != 3) {
if (!TestBit(TDataSetManager::kIsSandbox)) {
Error ("ParseUri", "illegal dataset path: '%s'", uri);
return kFALSE;
} else if (pc >= 0 && pc < 3) {
TString sls("/");
if (pc == 2) {
sls = "/";
} else if (pc == 1) {
sls.Form("/%s/", fGroup.Data());
} else if (pc == 0) {
sls.Form("/%s/%s/", fGroup.Data(), fUser.Data());
}
path.Insert(0, sls);
}
}
if (gDebug > 1)
Info("ParseUri", "path: '%s'", path.Data());
Int_t from = 1;
TString group, user, name;
path.Tokenize(group, from, "/");
path.Tokenize(user, from, "/");
path.Tokenize(name, from, "/");
TString tree = resolved.GetFragment();
if (tree.EndsWith("/"))
tree.Remove(tree.Length()-1);
if (gDebug > 1)
Info("ParseUri", "group: '%s', user: '%s', dsname:'%s', seg: '%s'",
group.Data(), user.Data(), name.Data(), tree.Data());
if ((user == "*" || group == "*") && !wildcards) {
Error ("ParseUri", "no wildcards allowed for user/group in this context (uri: '%s')", uri);
return kFALSE;
}
if (name.IsNull() && !wildcards) {
Error ("ParseUri", "DataSet name is empty");
return kFALSE;
}
TPRegexp wcExp (wildcards ? "^(?:[A-Za-z0-9-*_.]*|[*])$" : "^[A-Za-z0-9-_.]*$");
if (!wcExp.Match(group)) {
Error("ParseUri", "illegal characters in group (uri: '%s', group: '%s')", uri, group.Data());
return kFALSE;
}
if (!wcExp.Match(user)) {
Error("ParseUri", "illegal characters in user (uri: '%s', user: '%s')", uri, user.Data());
return kFALSE;
}
if (!wcExp.Match(name)) {
Error("ParseUri", "illegal characters in name (uri: '%s', name: '%s')", uri, name.Data());
return kFALSE;
}
if (tree.Contains(TRegexp("[^A-Za-z0-9-/_]"))) {
Error("ParseUri", "Illegal characters in subdir/object name (uri: '%s', obj: '%s')", uri, tree.Data());
return kFALSE;
}
if (onlyCurrent && (group.CompareTo(fGroup) || user.CompareTo(fUser))) {
Error("ParseUri", "only datasets from your group/user allowed");
return kFALSE;
}
if (dsGroup)
*dsGroup = group;
if (dsUser)
*dsUser = user;
if (dsName)
*dsName = name;
if (dsTree)
*dsTree = tree;
return kTRUE;
}
TMap *TDataSetManager::GetSubDataSets(const char *ds, const char *exclude)
{
TMap *map = (TMap *)0;
if (!ds || strlen(ds) <= 0) {
Info("GetDataSets", "dataset name undefined!");
return map;
}
TFileCollection *fc = GetDataSet(ds);
if (!fc) {
Info("GetDataSets", "could not retrieve the dataset '%s'", ds);
return map;
}
if (!(map = fc->GetFilesPerServer(exclude))) {
if (gDebug > 0)
Info("GetDataSets", "could not get map for '%s'", ds);
}
delete fc;
return map;
}
void TDataSetManager::PrintDataSet(TFileCollection *fc, Int_t popt)
{
if (!fc) return;
Int_t f = popt%10;
Int_t u = popt - 10 * f;
Printf("+++");
if (fc->GetTitle() && (strlen(fc->GetTitle()) > 0)) {
Printf("+++ Dumping: %s: ", fc->GetTitle());
} else {
Printf("+++ Dumping: %s: ", fc->GetName());
}
Printf("%s", fc->ExportInfo("+++ Summary:", 1)->GetName());
if (f == 1) {
Printf("+++ Files:");
Int_t nf = 0;
TIter nxfi(fc->GetList());
TFileInfo *fi = 0;
while ((fi = (TFileInfo *)nxfi())) {
if (u == 1)
Printf("+++ %5d. %s", ++nf, fi->GetCurrentUrl()->GetUrl());
else
Printf("+++ %5d. %s", ++nf, fi->GetCurrentUrl()->GetFile());
}
}
Printf("+++");
}
void TDataSetManager::ShowDataSets(const char *uri, const char *opt)
{
TFileCollection *fc = 0;
TString o(opt);
Int_t popt = 0;
if (o.Contains("full:")) {
o.ReplaceAll("full:","");
popt = 1;
}
if (o.BeginsWith("server:")) {
o.ReplaceAll("server:", "");
TString srv;
Int_t from = 0;
while ((o.Tokenize(srv, from, ","))) {
fc = GetDataSet(uri, srv.Data());
PrintDataSet(fc, popt);
delete fc;
}
} else if (o.BeginsWith("servers")) {
o.ReplaceAll("servers", "");
if (o.BeginsWith(":exclude:"))
o.ReplaceAll(":exclude:", "");
else
o = "";
TMap *dsmap = GetSubDataSets(uri, o.Data());
if (dsmap) {
TIter nxk(dsmap);
TObject *k = 0;
while ((k = nxk()) && (fc = (TFileCollection *) dsmap->GetValue(k))) {
PrintDataSet(fc, popt);
}
delete dsmap;
}
} else {
TString u(uri), grp, usr, dsn;
if (u == "" || u == "*" || u == "/*" || u == "/*/" || u == "/*/*") u = "/*/*/";
if (!ParseUri(u.Data(), &grp, &usr, &dsn, 0, kFALSE, kTRUE))
Warning("ShowDataSets", "problems parsing URI '%s'", uri);
UInt_t xopt = (UInt_t)(TDataSetManager::kPrint);
if (o.Contains("forcescan:")) xopt |= (UInt_t)(TDataSetManager::kForceScan);
if (o.Contains("noheader:")) xopt |= (UInt_t)(TDataSetManager::kNoHeaderPrint);
if (o.Contains("noupdate:")) xopt |= (UInt_t)(TDataSetManager::kNoCacheUpdate);
if (o.Contains("refresh:")) xopt |= (UInt_t)(TDataSetManager::kRefreshLs);
if (!u.IsNull() && !u.Contains("*") && !grp.IsNull() && !usr.IsNull() && !dsn.IsNull()) {
if (ExistsDataSet(uri)) {
if (popt == 0) {
GetDataSets(u.Data(), xopt);
} else if ((fc = GetDataSet(uri))) {
PrintDataSet(fc, 10 + popt);
delete fc;
}
return;
}
TRegexp reg(grp, kTRUE), reu(usr, kTRUE);
if (u.Index(reg) == kNPOS) grp = "*";
if (u.Index(reu) == kNPOS) usr = "*";
u.Form("/%s/%s/%s", grp.Data(), usr.Data(), dsn.Data());
}
GetDataSets(u.Data(), xopt);
}
return;
}
Int_t TDataSetManager::ScanDataSet(TFileCollection *dataset,
Int_t fopt, Int_t sopt, Int_t ropt, Bool_t dbg,
Int_t *touched, Int_t *opened, Int_t *disappeared,
TList *flist, Long64_t avgsz, const char *mss,
Int_t maxfiles, const char *stageopts)
{
if (maxfiles > -1 && dbg)
::Info("TDataSetManager::ScanDataSet", "processing a maximum of %d files", maxfiles);
Bool_t allf = (fopt == -1) ? kTRUE : kFALSE;
Bool_t checkstg = (fopt >= 100 || fopt < -1) ? kFALSE : kTRUE;
if (fopt >= 0) fopt %= 100;
Bool_t nonstgf = (fopt >= 0 && fopt < 10) ? kTRUE : kFALSE;
Bool_t reopen = (fopt >= 1 && fopt < 10) ? kTRUE : kFALSE;
Bool_t touch = (fopt >= 2 && fopt < 10) ? kTRUE : kFALSE;
Bool_t stgf = (fopt == 10) ? kTRUE : kFALSE;
Bool_t noaction = (sopt == -1) ? kTRUE : kFALSE;
Bool_t fullproc = (sopt == 0) ? kTRUE : kFALSE;
Bool_t locateonly = (sopt == 1) ? kTRUE : kFALSE;
Bool_t stageonly = (sopt == 2) ? kTRUE : kFALSE;
Bool_t doall = (ropt == 0) ? kTRUE : kFALSE;
Bool_t getlistonly = (ropt == 1) ? kTRUE : kFALSE;
Bool_t scanlist = (ropt == 2) ? kTRUE : kFALSE;
if (scanlist && !flist) {
::Error("TDataSetManager::ScanDataSet", "input list is mandatory for option 'scan file list'");
return -1;
}
Int_t ftouched = 0;
Int_t fopened = 0;
Int_t fdisappeared = 0;
Bool_t changed = kFALSE;
TList *newStagedFiles = 0;
TFileInfo *fileInfo = 0;
TFileStager *stager = 0;
Bool_t createStager = kFALSE;
if (doall || getlistonly) {
newStagedFiles = (!doall && getlistonly && flist) ? flist : new TList;
if (newStagedFiles != flist) newStagedFiles->SetOwner(kFALSE);
stager = (mss && strlen(mss) > 0) ? TFileStager::Open(mss) : 0;
createStager = (stager) ? kFALSE : kTRUE;
TIter iter2(dataset->GetList());
while ((fileInfo = (TFileInfo *) iter2())) {
gSystem->DispatchOneEvent(kTRUE);
if (!allf) {
fileInfo->ResetUrl();
if (!fileInfo->GetCurrentUrl()) {
::Error("TDataSetManager::ScanDataSet", "GetCurrentUrl() returned 0 for %s",
fileInfo->GetFirstUrl()->GetUrl());
continue;
}
if (nonstgf && fileInfo->TestBit(TFileInfo::kStaged)) {
if (fileInfo->TestBit(TFileInfo::kCorrupted)) continue;
if (!reopen) continue;
TUrl *curl = fileInfo->GetCurrentUrl();
const char *furl = curl->GetUrl();
TString urlmod;
if (TDataSetManager::CheckDataSetSrvMaps(curl, urlmod) && !(urlmod.IsNull()))
furl = urlmod.Data();
TUrl url(furl);
url.SetAnchor("");
if (dbg && (ftouched+fdisappeared) % 100 == 0)
::Info("TDataSetManager::ScanDataSet", "opening %d: file: %s",
ftouched + fdisappeared, curl->GetUrl());
TString uopt(url.GetOptions());
uopt += "filetype=raw&mxredir=2";
url.SetOptions(uopt.Data());
TFile *file = TFile::Open(url.GetUrl());
if (file) {
if (touch) {
char tmpChar = 0;
file->ReadBuffer(&tmpChar, 1);
ftouched++;
}
file->Close();
delete file;
} else {
if (dbg) ::Info("TDataSetManager::ScanDataSet", "file %s disappeared", url.GetUrl());
fileInfo->ResetBit(TFileInfo::kStaged);
fdisappeared++;
changed = kTRUE;
if (fileInfo->GetNUrls() > 1)
fileInfo->RemoveUrl(curl->GetUrl());
}
continue;
} else if (stgf && !(fileInfo->TestBit(TFileInfo::kStaged))) {
continue;
}
}
if (maxfiles > 0 && newStagedFiles->GetEntries() >= maxfiles)
continue;
if (checkstg) {
TUrl *curl = fileInfo->GetCurrentUrl();
const char *furl = curl->GetUrl();
TString urlmod;
Bool_t mapped = kFALSE;
if (TDataSetManager::CheckDataSetSrvMaps(curl, urlmod) && !(urlmod.IsNull())) {
furl = urlmod.Data();
mapped = kTRUE;
}
TUrl url(furl);
url.SetAnchor("");
stager = createStager ? TFileStager::Open(url.GetUrl()) : stager;
Bool_t result = kFALSE;
if (stager) {
result = stager->IsStaged(url.GetUrl());
if (gDebug > 0)
::Info("TDataSetManager::ScanDataSet", "IsStaged: %s: %d", url.GetUrl(), result);
if (createStager)
SafeDelete(stager);
} else {
::Warning("TDataSetManager::ScanDataSet",
"could not get stager instance for '%s'", url.GetUrl());
}
if (!result) {
if (fileInfo->TestBit(TFileInfo::kStaged)) {
fileInfo->ResetBit(TFileInfo::kStaged);
changed = kTRUE;
}
continue;
} else {
if (!(fileInfo->TestBit(TFileInfo::kStaged))) {
fileInfo->SetBit(TFileInfo::kStaged);
changed = kTRUE;
}
}
if (mapped) {
url.SetOptions(curl->GetOptions());
url.SetAnchor(curl->GetAnchor());
fileInfo->AddUrl(url.GetUrl(), kTRUE);
}
}
if (!noaction) newStagedFiles->Add(fileInfo);
}
SafeDelete(stager);
if (getlistonly) {
if (dbg && newStagedFiles->GetEntries() > 0)
::Info("TDataSetManager::ScanDataSet", " %d files appear to be newly staged",
newStagedFiles->GetEntries());
if (!flist) SafeDelete(newStagedFiles);
return ((changed) ? 2 : 1);
}
}
if (!noaction && (doall || scanlist)) {
newStagedFiles = (!doall && scanlist && flist) ? flist : newStagedFiles;
if (newStagedFiles != flist) newStagedFiles->SetOwner(kFALSE);
if (dbg && newStagedFiles->GetEntries() > 0)
::Info("TDataSetManager::ScanDataSet", "opening %d files that appear to be newly staged",
newStagedFiles->GetEntries());
if (locateonly || stageonly) {
stager = (mss && strlen(mss) > 0) ? TFileStager::Open(mss) : 0;
createStager = (stager) ? kFALSE : kTRUE;
}
Int_t fqnot = (newStagedFiles->GetSize() > 10) ? newStagedFiles->GetSize() / 10 : 1;
if (fqnot > 100) fqnot = 100;
Int_t count = 0;
TIter iter3(newStagedFiles);
while ((fileInfo = (TFileInfo *) iter3())) {
if (dbg && (count%fqnot == 0))
::Info("TDataSetManager::ScanDataSet", "processing %d.'new' file: %s",
count, fileInfo->GetCurrentUrl()->GetUrl());
count++;
gSystem->DispatchOneEvent(kTRUE);
Int_t rc = -1;
TUrl *curl = fileInfo->GetCurrentUrl();
const char *furl = curl->GetUrl();
TString urlmod;
Bool_t mapped = kFALSE;
if (TDataSetManager::CheckDataSetSrvMaps(curl, urlmod) && !(urlmod.IsNull())) {
furl = urlmod.Data();
mapped = kTRUE;
}
TUrl url(furl);
url.SetOptions("");
url.SetAnchor("");
if (createStager) {
if (!stager || (stager && !stager->Matches(url.GetUrl()))) {
SafeDelete(stager);
if (!(stager = TFileStager::Open(url.GetUrl())) || !(stager->IsValid())) {
::Error("TDataSetManager::ScanDataSet",
"could not get valid stager instance for '%s'", url.GetUrl());
continue;
}
}
}
if (locateonly) {
TString eurl;
if (stager && stager->Locate(url.GetUrl(), eurl) == 0) {
TString opts(curl->GetOptions());
TString anch(curl->GetAnchor());
curl->SetUrl(eurl);
curl->SetOptions(opts);
curl->SetAnchor(anch);
changed = kTRUE;
fopened++;
} else {
::Error("TDataSetManager::ScanDataSet", "could not locate %s", url.GetUrl());
}
} else if (stageonly) {
if (stager && !(stager->IsStaged(url.GetUrl()))) {
if (!(stager->Stage(url.GetUrl(), stageopts))) {
::Error("TDataSetManager::ScanDataSet",
"problems issuing stage request for %s", url.GetUrl());
}
}
} else if (fullproc) {
rc = -2;
Bool_t doscan = kTRUE;
if (checkstg) {
doscan = kFALSE;
if ((doall && fileInfo->TestBit(TFileInfo::kStaged)) ||
(stager && stager->IsStaged(url.GetUrl()))) doscan = kTRUE;
}
if (doscan) {
if ((rc = TDataSetManager::ScanFile(fileInfo, dbg)) < -1) continue;
changed = kTRUE;
} else if (stager) {
::Warning("TDataSetManager::ScanDataSet",
"required file '%s' does not look as being online (staged)", url.GetUrl());
}
if (rc < 0) continue;
fopened++;
}
}
if (newStagedFiles != flist) SafeDelete(newStagedFiles);
dataset->RemoveDuplicates();
dataset->Update(avgsz);
}
Int_t result = (changed) ? 2 : 1;
if (result > 0 && dbg)
::Info("TDataSetManager::ScanDataSet", "%d files 'new'; %d files touched;"
" %d files disappeared", fopened, ftouched, fdisappeared);
if (touched) *touched = ftouched;
if (opened) *opened = fopened;
if (disappeared) *disappeared = fdisappeared;
gSystem->DispatchOneEvent(kTRUE);
return result;
}
Int_t TDataSetManager::ScanFile(TFileInfo *fileinfo, Bool_t dbg)
{
Int_t rc = -2;
if (!fileinfo) {
::Error("TDataSetManager::ScanFile", "undefined input (!)");
return rc;
}
TUrl *url = fileinfo->GetCurrentUrl();
TFile *file = 0;
const char *furl = url->GetUrl();
TString urlmod;
if (TDataSetManager::CheckDataSetSrvMaps(url, urlmod) && !(urlmod.IsNull()))
furl = urlmod.Data();
TUrl urlNoAnchor(furl);
urlNoAnchor.SetAnchor("");
urlNoAnchor.SetOptions("filetype=raw");
if (!(file = TFile::Open(urlNoAnchor.GetUrl(), "TIMEOUT=5"))) return rc;
rc = -1;
fileinfo->SetBit(TFileInfo::kStaged);
TUrl eurl(*(file->GetEndpointUrl()));
eurl.SetOptions(url->GetOptions());
eurl.SetAnchor(url->GetAnchor());
fileinfo->AddUrl(eurl.GetUrl(), kTRUE);
if (gDebug > 0) ::Info("TDataSetManager::ScanFile", "added URL %s", eurl.GetUrl());
if (file->GetSize() > 0) fileinfo->SetSize(file->GetSize());
fileinfo->SetUUID(file->GetUUID().AsString());
file->Close();
delete file;
Int_t oldLevel = gErrorIgnoreLevel;
gErrorIgnoreLevel = kError+1;
if (!(file = TFile::Open(url->GetUrl(), "TIMEOUT=5"))) {
if (dbg) ::Info("TDataSetManager::ScanFile", "marking %s as corrupt", url->GetUrl());
fileinfo->SetBit(TFileInfo::kCorrupted);
gErrorIgnoreLevel = oldLevel;
return rc;
}
rc = 0;
if ((rc = TDataSetManager::FillMetaData(fileinfo, file, "/")) != 0) {
::Error("TDataSetManager::ScanFile",
"problems processing the directory tree in looking for metainfo");
}
gErrorIgnoreLevel = oldLevel;
file->Close();
delete file;
return rc;
}
Int_t TDataSetManager::FillMetaData(TFileInfo *fi, TDirectory *d, const char *rdir)
{
if (!fi || !d || !rdir) {
::Error("TDataSetManager::FillMetaData",
"some inputs are invalid (fi:%p,d:%p,r:%s)", fi, d, rdir);
return -1;
}
if (d->GetListOfKeys()) {
TIter nxk(d->GetListOfKeys());
TKey *k = 0;
while ((k = dynamic_cast<TKey *> (nxk()))) {
if (TClass::GetClass(k->GetClassName())->InheritsFrom(TDirectory::Class())) {
TDirectory *sd = (TDirectory *) d->Get(k->GetName());
if (!sd) {
::Error("TDataSetManager::FillMetaData", "cannot get sub-directory '%s'", k->GetName());
return -1;
}
if (TDataSetManager::FillMetaData(fi, sd, TString::Format("%s%s/", rdir, k->GetName())) != 0) {
::Error("TDataSetManager::FillMetaData", "problems processing sub-directory '%s'", k->GetName());
return -1;
}
} else {
if (!TClass::GetClass(k->GetClassName())->InheritsFrom(TTree::Class())) continue;
TString ks;
ks.Form("%s%s", rdir, k->GetName());
TFileInfoMeta *md = fi->GetMetaData(ks);
if (!md) {
md = new TFileInfoMeta(ks, k->GetClassName());
fi->AddMetaData(md);
if (gDebug > 0)
::Info("TDataSetManager::FillMetaData", "created meta data for tree %s", ks.Data());
}
TTree *t = dynamic_cast<TTree *> (d->Get(k->GetName()));
if (t) {
if (t->GetEntries() >= 0) {
md->SetEntries(t->GetEntries());
if (t->GetTotBytes() >= 0)
md->SetTotBytes(t->GetTotBytes());
if (t->GetZipBytes() >= 0)
md->SetZipBytes(t->GetZipBytes());
}
} else {
::Error("TDataSetManager::FillMetaData", "could not get tree '%s'", k->GetName());
return -1;
}
}
}
}
return 0;
}
TList *TDataSetManager::ParseDataSetSrvMaps(const TString &srvmaps)
{
TList *srvmapslist = 0;
if (srvmaps.IsNull()) {
::Warning("TDataSetManager::ParseDataSetSrvMaps",
"called with an empty string! - nothing to do");
return srvmapslist;
}
TString srvmap, sf, st;
Int_t from = 0, from1 = 0;
while (srvmaps.Tokenize(srvmap, from, " ")) {
sf = ""; st = "";
if (srvmap.Contains("|")) {
from1 = 0;
if (srvmap.Tokenize(sf, from1, "|")) srvmap.Tokenize(st, from1, "|");
} else {
st = srvmap;
}
if (st.IsNull()) {
::Warning("TDataSetManager::ParseDataSetSrvMaps",
"parsing DataSet.SrvMaps: target must be defined"
" (token: %s) - ignoring", srvmap.Data());
continue;
} else if (!(st.EndsWith("/"))) {
st += "/";
}
TString sp;
TUrl *u = 0;
if (!(sf.IsNull()) && sf.Contains("*")) {
u = new TUrl(sf);
if (!(sf.BeginsWith(u->GetProtocol()))) u->SetProtocol("root");
sp.Form(":%d", u->GetPort());
if (!(sf.Contains(sp))) u->SetPort(1094);
if (!TString(u->GetHost()).Contains("*")) SafeDelete(u);
}
if (!srvmapslist) srvmapslist = new TList;
if (u) {
srvmapslist->Add(new TPair(u, new TObjString(st)));
} else {
srvmapslist->Add(new TPair(new TObjString(sf), new TObjString(st)));
}
}
if (srvmapslist) srvmapslist->SetOwner(kTRUE);
return srvmapslist;
}
TList *TDataSetManager::GetDataSetSrvMaps()
{
return fgDataSetSrvMaps;
}
Bool_t TDataSetManager::CheckDataSetSrvMaps(TUrl *furl, TString &file1, TList *srvmaplist)
{
Bool_t replaced = kFALSE;
if (!furl) return replaced;
const char *file = furl->GetUrl();
TList *mlist = (srvmaplist) ? srvmaplist : fgDataSetSrvMaps;
if (mlist && mlist->GetSize() > 0) {
TIter nxm(mlist);
TPair *pr = 0;
while ((pr = (TPair *) nxm())) {
Bool_t replace = kFALSE;
TUrl *u = dynamic_cast<TUrl *>(pr->Key());
if (u) {
if (!strcmp(u->GetProtocol(), furl->GetProtocol())) {
Ssiz_t len;
if (!strcmp(u->GetProtocol(), "file")) {
TRegexp re(u->GetFileAndOptions(), kTRUE);
if (re.Index(furl->GetFileAndOptions(), &len) == 0) replace = kTRUE;
} else {
if (u->GetPort() == furl->GetPort()) {
TRegexp re(u->GetHost(), kTRUE);
if (re.Index(furl->GetHost(), &len) == 0) replace = kTRUE;
}
}
}
} else {
TObjString *os = dynamic_cast<TObjString *>(pr->Key());
if (os) {
if (os->GetString().IsNull() ||
!strncmp(file, os->GetName(), os->GetString().Length())) replace = kTRUE;
}
}
if (replace) {
TObjString *ost = dynamic_cast<TObjString *>(pr->Value());
if (ost) {
file1.Form("%s%s", ost->GetName(), furl->GetFileAndOptions());
replaced = kTRUE;
break;
}
}
}
}
return replaced;
}
void TDataSetManager::SetScanCounters(Int_t t, Int_t o, Int_t d)
{
fNTouchedFiles = (t > -1) ? t : fNTouchedFiles;
fNOpenedFiles = (o > -1) ? o : fNOpenedFiles;
fNDisappearedFiles = (d > -1) ? d : fNDisappearedFiles;
}