XrdProofGroup.cxx

Go to the documentation of this file.
00001 // @(#)root/proofd:$Id: XrdProofGroup.cxx 36520 2010-11-05 16:08:23Z ganis $
00002 // Author: Gerardo Ganis  June 2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // XrdProofGroup                                                        //
00015 //                                                                      //
00016 // Authors: G. Ganis, CERN, 2007                                        //
00017 //                                                                      //
00018 // Class describing groups                                              //
00019 //                                                                      //
00020 //////////////////////////////////////////////////////////////////////////
00021 #include "XrdProofdPlatform.h"
00022 
00023 #include "XrdProofGroup.h"
00024 #include "XrdProofdTrace.h"
00025 
00026 // Functions used in scanning hash tables
00027 
00028 //__________________________________________________________________________
00029 static int CheckUser(const char *, XrdProofGroup *g, void *u)
00030 {
00031    // Check if user 'u' is memmebr of group 'grp'
00032 
00033    const char *usr = (const char *)u;
00034 
00035    if (g && usr && g->HasMember(usr))
00036       // Found the group
00037       return 1;
00038 
00039    // Check next
00040    return 0;
00041 }
00042 
00043 //__________________________________________________________________________
00044 static int ExportGroup(const char *, XrdProofGroup *g, void *u)
00045 {
00046    // Add a string describing group 'g' to a global string
00047 
00048    XrdOucString *msg = (XrdOucString *)u;
00049 
00050    if (msg->length() > 0)
00051       *msg += '\n';
00052 
00053    *msg = g->Name(); *msg += ": ";
00054    *msg += ", size: ";
00055    *msg += g->Size();
00056    *msg += ", members(s): ";
00057    *msg += g->Members();
00058 
00059    return 0;
00060 }
00061 
00062 //__________________________________________________________________________
00063 static int PrintGroup(const char *, XrdProofGroup *g, void *)
00064 {
00065    // Print info describing group 'g' to stdout
00066 
00067    if (g)
00068       g->Print();
00069 
00070    return 0;
00071 }
00072 
00073 //__________________________________________________________________________
00074 static int AuxFunc(const char *, XrdProofGroup *g, void *s)
00075 {
00076    // Generic function used for auxiliary purpose
00077 
00078    XrdOucString *opt = (XrdOucString *)s;
00079 
00080    if (!opt || opt->length() <= 0 || (*opt) == "getfirst")
00081       // Stop going through the table
00082       return 1;
00083 
00084    if (opt->beginswith("getnextgrp:")) {
00085       XrdOucString grp("||");
00086       grp.insert(g->Name(),1);
00087       if (opt->find(grp) == STR_NPOS) {
00088          *opt += grp;
00089          return 1;
00090       }
00091    }
00092 
00093    // Process next
00094    return 0;
00095 }
00096 
00097 //__________________________________________________________________________
00098 XrdProofGroup::XrdProofGroup(const char *n, const char *m)
00099               : fName(n), fMembers(m)
00100 {
00101    // Constructor
00102 
00103    fSize = 0;
00104    fPriority = -1;
00105    fFraction = -1;
00106    fFracEff = 0;
00107    fMutex = new XrdSysRecMutex;
00108 }
00109 //__________________________________________________________________________
00110 XrdProofGroup::~XrdProofGroup()
00111 {
00112    // Destructor
00113 
00114    if (fMutex)
00115       delete fMutex;
00116    fMutex = 0;
00117 }
00118 
00119 //__________________________________________________________________________
00120 void XrdProofGroup::Print()
00121 {
00122    // Dump group content
00123    XPDLOC(GMGR, "Group::Print")
00124 
00125    XrdSysMutexHelper mhp(fMutex); 
00126 
00127    if (fName != "default") {
00128       TRACE(ALL, "+++ Group: "<<fName<<", size "<<fSize<<" member(s) ("<<fMembers<<")");
00129       TRACE(ALL, "+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
00130       TRACE(ALL, "+++ End of Group: "<<fName);
00131    } else {
00132       TRACE(ALL, "+++ Group: "<<fName);
00133       TRACE(ALL, "+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
00134       TRACE(ALL, "+++ End of Group: "<<fName);
00135    }
00136 }
00137 
00138 //__________________________________________________________________________
00139 void XrdProofGroup::Count(const char *usr, int n)
00140 {
00141    // Modify the active count
00142 
00143    // A username must be defined and an action required
00144    if (!usr || strlen(usr) == 0 || n == 0)
00145       return;
00146 
00147    XrdSysMutexHelper mhp(fMutex);
00148 
00149    XrdProofGroupMember *m = fActives.Find(usr);
00150    if (!m) {
00151       // Create a new active user
00152       m = new XrdProofGroupMember(usr);
00153       fActives.Add(usr, m);
00154    }
00155 
00156    // Count
00157    if (m) {
00158       m->Count(n);
00159       // If no active sessions left, remove from active
00160       if (m->Active() <= 0) {
00161          fActives.Del(usr);
00162          delete m;
00163       }
00164    }
00165 }
00166 
00167 //__________________________________________________________________________
00168 int XrdProofGroup::Active(const char *usr)
00169 {
00170    // Return the number of active groups (usr = 0) or the number of
00171    // active sessions for user 'usr'
00172 
00173    XrdSysMutexHelper mhp(fMutex);
00174 
00175    int na = 0;
00176    if (!usr || strlen(usr) == 0) {
00177       na = fActives.Num();
00178    } else {
00179       XrdProofGroupMember *m = fActives.Find(usr);
00180       if (m) na = m->Active();
00181    }
00182    // Done
00183    return na;
00184 }
00185 
00186 //__________________________________________________________________________
00187 bool XrdProofGroup::HasMember(const char *usr)
00188 {
00189    // Check if 'usr' is member of this group
00190 
00191    XrdSysMutexHelper mhp(fMutex);
00192    XrdOucString u(usr); u += ",";
00193    int iu = fMembers.find(u);
00194    if (iu != STR_NPOS)
00195       if (iu == 0 || fMembers[iu-1] == ',')
00196          return 1;
00197    return 0;
00198 }
00199 
00200 //__________________________________________________________________________
00201 XrdProofGroupMgr::XrdProofGroupMgr(const char *fn)
00202 {
00203    // Constructor
00204 
00205    ResetIter(); 
00206    Config(fn);
00207 }
00208 
00209 //__________________________________________________________________________
00210 XrdProofGroup *XrdProofGroupMgr::Apply(int (*f)(const char *, XrdProofGroup *,
00211                                                 void *), void *arg)
00212 {
00213    // Apply function 'f' to the hash table of groups; 'arg' is passed to 'f'
00214    // in the last argument. After applying 'f', the action depends on the
00215    // return value with the following rule:
00216    //         < 0 - the hash table item is deleted.
00217    //         = 0 - the next hash table item is processed.
00218    //         > 0 - processing stops and the hash table item is returned.
00219 
00220    return (fGroups.Num() > 0 ? fGroups.Apply(f,arg) : (XrdProofGroup *)0);
00221 }
00222 
00223 //__________________________________________________________________________
00224 XrdOucString XrdProofGroupMgr::Export(const char *grp)
00225 {
00226    // Return a string describing the group
00227 
00228    XrdSysMutexHelper mhp(fMutex); 
00229 
00230    XrdOucString msg;
00231 
00232    if (!grp) {
00233       fGroups.Apply(ExportGroup, (void *) &msg);
00234    } else {
00235       XrdProofGroup *g = fGroups.Find(grp);
00236       ExportGroup(grp, g, (void *) &msg);
00237    }
00238 
00239    return msg;
00240 }
00241 
00242 //__________________________________________________________________________
00243 void XrdProofGroupMgr::Print(const char *grp)
00244 {
00245    // Return a string describing the group
00246 
00247    XrdSysMutexHelper mhp(fMutex); 
00248 
00249    if (!grp) {
00250       fGroups.Apply(PrintGroup, 0);
00251    } else {
00252       XrdProofGroup *g = fGroups.Find(grp);
00253       PrintGroup(grp, g, 0);
00254    }
00255 
00256    return;
00257 }
00258 
00259 //__________________________________________________________________________
00260 XrdProofGroup *XrdProofGroupMgr::GetGroup(const char *grp)
00261 {
00262    // Returns the instance of for group 'grp.
00263    // Return 0 in the case the group does not exist
00264 
00265    // If the group is defined and exists, check it 
00266    if (grp && strlen(grp) > 0) {
00267       XrdSysMutexHelper mhp(fMutex);
00268       return fGroups.Find(grp);
00269    }
00270    return (XrdProofGroup *)0;
00271 }
00272 
00273 //__________________________________________________________________________
00274 XrdProofGroup *XrdProofGroupMgr::GetUserGroup(const char *usr, const char *grp)
00275 {
00276    // Returns the instance of the first group to which this user belongs;
00277    // if grp != 0, return the instance corresponding to group 'grp', if
00278    // existing and the // user belongs to it.
00279    // Return 0 in the case the user does not belong to any group or does not
00280    // belong to 'grp'.
00281 
00282    XrdProofGroup *g = 0;
00283 
00284    // Check inputs
00285    if (!usr || strlen(usr) <= 0)
00286       return g;
00287 
00288    XrdSysMutexHelper mhp(fMutex);
00289 
00290    // If the group is defined and exists, check it 
00291    if (grp && strlen(grp) > 0) {
00292       g = fGroups.Find(grp);
00293       if (g && (!strncmp(g->Name(),"default",7) || g->HasMember(usr)))
00294          return g;
00295       else
00296          return (XrdProofGroup *)0;
00297    }
00298 
00299    // Scan the table
00300    g = fGroups.Apply(CheckUser, (void *)usr);
00301 
00302    // Assign to "default" group if nothing was found
00303    return ((!g) ? fGroups.Find("default") : g);
00304 }
00305 
00306 //__________________________________________________________________________
00307 XrdProofGroup *XrdProofGroupMgr::Next()
00308 {
00309    // Returns the instance of next group in the pseudo-iterator
00310    // functionality. To scan over all the groups do the following:
00311    //         ResetIter();
00312    //         while ((g = Next())) {
00313    //            // ... Process group
00314    //         }
00315    // Return 0 when there are no more groups
00316 
00317    return fGroups.Apply(AuxFunc,&fIterator);
00318 }
00319 
00320 //__________________________________________________________________________
00321 int XrdProofGroupMgr::Config(const char *fn)
00322 {
00323    // (Re-)configure the group info using the file 'fn'.
00324    // Return the number of active groups or -1 in case of error.
00325    XPDLOC(GMGR, "GroupMgr::Config")
00326 
00327    if (!fn || strlen(fn) <= 0) {
00328       // This call is to reset existing info and remain with
00329       // the 'default' group only
00330       XrdSysMutexHelper mhp(fMutex);
00331       // Reset existing info
00332       fGroups.Purge();
00333       // Create "default" group
00334       fGroups.Add("default", new XrdProofGroup("default"));
00335       return fGroups.Num();;
00336    }
00337 
00338    // Did the file changed ?
00339    if (fCfgFile.fName != fn) {
00340       fCfgFile.fName = fn;
00341       XrdProofdAux::Expand(fCfgFile.fName);
00342       fCfgFile.fMtime = 0;
00343    }
00344 
00345    // Get the modification time
00346    struct stat st;
00347    if (stat(fCfgFile.fName.c_str(), &st) != 0)
00348       return -1;
00349    TRACE(DBG, "enter: time of last modification: " << st.st_mtime);
00350 
00351    // Nothing to do if the file did not change
00352    if (st.st_mtime <= fCfgFile.fMtime) return fGroups.Num();
00353    
00354    // Save the modification time
00355    fCfgFile.fMtime = st.st_mtime;
00356 
00357    // This part must be modified in atomic way
00358    XrdSysMutexHelper mhp(fMutex);
00359 
00360    // Reset existing info
00361    fGroups.Purge();
00362 
00363    // Create "default" group
00364    fGroups.Add("default", new XrdProofGroup("default"));
00365 
00366    // Read now the directives (recursive processing of 'include sub-file'
00367    // in here)
00368    if (ParseInfoFrom(fCfgFile.fName.c_str()) != 0) {
00369       TRACE(XERR, "problems parsing config file "<<fCfgFile.fName);
00370    }
00371    
00372    // Notify the content
00373    Print(0);
00374 
00375    // Return the number of active groups
00376    return fGroups.Num();
00377 }
00378 
00379 //__________________________________________________________________________
00380 int XrdProofGroupMgr::ParseInfoFrom(const char *fn)
00381 {
00382    // Parse config information from the open file 'fin'. Can be called
00383    // recursively following 'include sub-file' lines.
00384    // Return 0 or -1 in case of error.
00385    XPDLOC(GMGR, "GroupMgr::ParseInfoFrom")
00386 
00387    // Check input
00388    if (!fn || strlen(fn) <= 0) {
00389       TRACE(XERR, "file name undefined!");
00390       return -1;
00391    }
00392 
00393    // Open the defined path.
00394    FILE *fin = 0;
00395    if (!(fin = fopen(fn, "r"))) {
00396       TRACE(XERR, "cannot open file: "<<fn<<" (errno:"<<errno<<")");
00397       return -1;
00398    }
00399 
00400    // Read now the directives
00401    char lin[2048];
00402    while (fgets(lin,sizeof(lin),fin)) {
00403       // Remove trailing '\n'
00404       if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
00405       // Skip comments or empty lines
00406       if (lin[0] == '#' || strlen(lin) <= 0) continue;
00407       // Good line: parse it
00408       bool gotkey = 0, gotgrp = 0;
00409       XrdOucString gl(lin), tok, key, group;
00410       gl.replace(" ",",");
00411       int from = 0;
00412       while ((from = gl.tokenize(tok, from, ',')) != -1) {
00413          if (tok.length() > 0) {
00414             if (!gotkey) {
00415                key = tok;
00416                gotkey = 1;
00417             } else if (!gotgrp) {
00418                group = tok;
00419                gotgrp = 1;
00420                break;
00421             }
00422          }
00423       }
00424       // Check consistency
00425       if (!gotkey || !gotgrp) {
00426          // Insufficient info
00427          TRACE(DBG, "incomplete line: " << lin);
00428          continue;
00429       }
00430 
00431       if (key == "include") {
00432          // File to be included in the parsing
00433          XrdOucString subfn = group;
00434          // Expand the path
00435          XrdProofdAux::Expand(subfn);
00436          // Process it
00437          if (ParseInfoFrom(subfn.c_str()) != 0) {
00438             TRACE(XERR, "problems parsing included file "<<subfn);
00439          }
00440          continue;
00441       }
00442 
00443       if (key == "priorityfile") {
00444          // File from which (updated) priorities are read
00445          fPriorityFile.fName = group;
00446          XrdProofdAux::Expand(fPriorityFile.fName);
00447          fPriorityFile.fMtime = 0;
00448          continue;
00449       }
00450 
00451       // Get linked to the group, if any
00452       XrdProofGroup *g = fGroups.Find(group.c_str());
00453 
00454       // Action depends on key
00455       if (key == "group") {
00456          if (!g)
00457             // Create new group container
00458             fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
00459          while ((from = gl.tokenize(tok, from, ',')) != -1) {
00460             if (tok.length() > 0)
00461                // Add group member
00462                g->AddMember(tok.c_str());
00463          }
00464       } else if (key == "property") {
00465          // Property definition: format of property is
00466          // property <group> <property_name> <nominal_value> [<effective_value>]
00467          XrdOucString name;
00468          int nom=0;
00469          bool gotname = 0, gotnom = 0;
00470          while ((from = gl.tokenize(tok, from, ',')) != -1) {
00471             if (tok.length() > 0) {
00472                if (!gotname) {
00473                   name = tok;
00474                   gotname= 1;
00475                } else if (!gotnom) {
00476                   nom = atoi(tok.c_str());
00477                   gotnom = 1;
00478                   break;
00479                }
00480             }
00481          }
00482          if (!gotname || !gotnom) {
00483             // Insufficient info
00484             TRACE(DBG, "incomplete property line: " << lin);
00485             continue;
00486          }
00487          if (!g)
00488             // Create new group container
00489             fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
00490          if (name == "priority")
00491             g->SetPriority((float)nom);
00492          if (name == "fraction")
00493             g->SetFraction(nom);
00494       }
00495    }
00496    // Close this file
00497    fclose(fin);
00498    // Done
00499    return 0;
00500 }
00501 
00502 //__________________________________________________________________________
00503 int XrdProofGroupMgr::ReadPriorities()
00504 {
00505    // Read update priorities from the file defined at configuration time.
00506    // Return 1 if the file did not change, 0 if the file has been read
00507    // correctly, or -1 in case of error.
00508    XPDLOC(GMGR, "GroupMgr::ReadPriorities")
00509 
00510    // Get the modification time
00511    struct stat st;
00512    if (stat(fPriorityFile.fName.c_str(), &st) != 0)
00513       return -1;
00514    TRACE(DBG, "time of last modification: " << st.st_mtime);
00515 
00516    // File should be loaded only once
00517    if (st.st_mtime <= fPriorityFile.fMtime) {
00518       TRACE(DBG, "file unchanged since last reading - do nothing ");
00519       return 1;
00520    }
00521 
00522    // Save the modification time
00523    fPriorityFile.fMtime = st.st_mtime;
00524 
00525    // Open the defined path.
00526    FILE *fin = 0;
00527    if (!(fin = fopen(fPriorityFile.fName.c_str(), "r"))) {
00528       TRACE(XERR, "cannot open file: "<<fPriorityFile.fName<<" (errno:"<<errno<<")");
00529       return -1;
00530    }
00531 
00532    // This part must be modified in atomic way
00533    XrdSysMutexHelper mhp(fMutex);
00534 
00535    // Read now the directives
00536    char lin[2048];
00537    while (fgets(lin,sizeof(lin),fin)) {
00538       // Remove trailing '\n'
00539       if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
00540       // Skip comments or empty lines
00541       if (lin[0] == '#' || strlen(lin) <= 0) continue;
00542       // Good line candidate: parse it
00543       XrdOucString gl(lin), group, value;
00544       // It must contain a '='
00545       int from = 0;
00546       if ((from = gl.tokenize(group, 0, '=')) == -1)
00547          continue;
00548       // Get linked to the group, if any
00549       XrdProofGroup *g = fGroups.Find(group.c_str());
00550       if (!g) {
00551          TRACE(XERR, "found info for unknown group: "<<group<<" - ignoring");
00552          continue;
00553       }
00554       gl.tokenize(value, from, '=');
00555       if (value.length() <= 0) {
00556          TRACE(XERR, "value missing: read line is: '"<<gl<<"'");
00557          continue;
00558       }
00559       // Transform it in a usable value 
00560       if (value.find('.') == STR_NPOS)
00561          value += '.';
00562       // Save it
00563       g->SetPriority((float)strtod(value.c_str(),0));
00564    }
00565 
00566    // Done
00567    return 0;
00568 }
00569 
00570 //__________________________________________________________________________
00571 static int GetGroupsInfo(const char *, XrdProofGroup *g, void *s)
00572 {
00573    // Fill the global group structure
00574 
00575    XpdGroupGlobal_t *glo = (XpdGroupGlobal_t *)s;
00576 
00577    if (glo) {
00578       if (g->Active() > 0) {
00579          // Set the min/max priorities
00580          if (glo->prmin == -1 || g->Priority() < glo->prmin)
00581             glo->prmin = g->Priority();
00582          if (glo->prmax == -1 || g->Priority() > glo->prmax)
00583             glo->prmax = g->Priority();
00584          // Set the draft fractions
00585          if (g->Fraction() > 0) {
00586             g->SetFracEff((float)(g->Fraction()));
00587             glo->totfrac += (float)(g->Fraction());
00588          } else {
00589             glo->nofrac += 1;
00590          }
00591       }
00592    } else {
00593       // Not enough info: stop
00594       return 1;
00595    }
00596 
00597    // Check next
00598    return 0;
00599 }
00600 
00601 //__________________________________________________________________________
00602 static int SetGroupFracEff(const char *, XrdProofGroup *g, void *s)
00603 {
00604    // Check if user 'u' is memmebr of group 'grp'
00605 
00606    XpdGroupEff_t *eff = (XpdGroupEff_t *)s;
00607 
00608    if (eff && eff->glo) {
00609       XpdGroupGlobal_t *glo = eff->glo;
00610       if (g->Active() > 0) {
00611          if (eff->opt == 0) {
00612             float ef = g->Priority() / glo->prmin;
00613             g->SetFracEff(ef);
00614          } else if (eff->opt == 1) {
00615             if (g->Fraction() < 0) {
00616                float ef = ((100. - glo->totfrac) / glo->nofrac);
00617                g->SetFracEff(ef);
00618             }
00619          } else if (eff->opt == 2) {
00620             if (g->FracEff() < 0) {
00621                // Share eff->cut (default 5%) between those with undefined fraction
00622                float ef = (eff->cut / glo->nofrac);
00623                g->SetFracEff(ef);
00624             } else {
00625                // renormalize
00626                float ef = g->FracEff() * eff->norm;
00627                g->SetFracEff(ef);
00628             }
00629          }
00630       }
00631    } else {
00632       // Not enough info: stop
00633       return 1;
00634    }
00635 
00636    // Check next
00637    return 0;
00638 }
00639 
00640 //______________________________________________________________________________
00641 int XrdProofGroupMgr::SetEffectiveFractions(bool opri)
00642 {
00643    // Go through the list of active groups (those having at least a non-idle
00644    // member) and determine the effective resource fraction on the base of
00645    // the scheduling option and of priorities or nominal fractions.
00646    // Return 0 in case of success, -1 in case of error, 1 if every group
00647    // has the same priority so that the system scheduler should do the job.
00648 
00649    // Loop over groupd
00650    XpdGroupGlobal_t glo = {-1., -1., 0, 0.};
00651    Apply(GetGroupsInfo, &glo);
00652 
00653    XpdGroupEff_t eff = {0, &glo, 0.5, 1.};
00654    if (opri) {
00655       // Set effective fractions
00656       ResetIter();
00657       eff.opt = 0;
00658       Apply(SetGroupFracEff, &eff);
00659 
00660    } else {
00661       // In the fraction scheme we need to fill up with the remaining resources
00662       // if at least one lower bound was found. And of course we need to restore
00663       // unitarity, if it was broken
00664 
00665       if (glo.totfrac < 100. && glo.nofrac > 0) {
00666          eff.opt = 1;
00667          Apply(SetGroupFracEff, &eff);
00668       } else if (glo.totfrac > 100) {
00669          // Leave 5% for unnamed or low priority groups
00670          eff.opt = 2;
00671          eff.norm = (glo.nofrac > 0) ? (100. - eff.cut)/glo.totfrac : 100./glo.totfrac ;
00672          Apply(SetGroupFracEff, &eff);
00673       }
00674    }
00675 
00676    // Done
00677    return 0;
00678 }

Generated on Tue Jul 5 14:51:52 2011 for ROOT_528-00b_version by  doxygen 1.5.1