Logo ROOT   6.18/05
Reference Guide
XrdProofGroup.cxx
Go to the documentation of this file.
1// @(#)root/proofd:$Id$
2// Author: Gerardo Ganis June 2007
3
4/*************************************************************************
5 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//////////////////////////////////////////////////////////////////////////
13// //
14// XrdProofGroup //
15// //
16// Authors: G. Ganis, CERN, 2007 //
17// //
18// Class describing groups //
19// //
20//////////////////////////////////////////////////////////////////////////
21#include "XrdProofdPlatform.h"
22
23#include "XrdProofGroup.h"
24#include "XrdProofdTrace.h"
25
26// Functions used in scanning hash tables
27
28////////////////////////////////////////////////////////////////////////////////
29/// Check if user 'u' is memmebr of group 'grp'
30
31static int CheckUser(const char *, XrdProofGroup *g, void *u)
32{
33 const char *usr = (const char *)u;
34
35 if (g && usr && g->HasMember(usr))
36 // Found the group
37 return 1;
38
39 // Check next
40 return 0;
41}
42
43////////////////////////////////////////////////////////////////////////////////
44/// Add a string describing group 'g' to a global string
45
46static int ExportGroup(const char *, XrdProofGroup *g, void *u)
47{
48 XrdOucString *msg = (XrdOucString *)u;
49
50 if (msg->length() > 0)
51 *msg += '\n';
52
53 *msg = g->Name(); *msg += ": ";
54 *msg += ", size: ";
55 *msg += g->Size();
56 *msg += ", members(s): ";
57 *msg += g->Members();
58
59 return 0;
60}
61
62////////////////////////////////////////////////////////////////////////////////
63/// Print info describing group 'g' to stdout
64
65static int PrintGroup(const char *, XrdProofGroup *g, void *)
66{
67 if (g)
68 g->Print();
69
70 return 0;
71}
72
73////////////////////////////////////////////////////////////////////////////////
74/// Generic function used for auxiliary purpose
75
76static int AuxFunc(const char *, XrdProofGroup *g, void *s)
77{
78 XrdOucString *opt = (XrdOucString *)s;
79
80 if (!opt || opt->length() <= 0 || (*opt) == "getfirst")
81 // Stop going through the table
82 return 1;
83
84 if (opt->beginswith("getnextgrp:")) {
85 XrdOucString grp("||");
86 grp.insert(g->Name(),1);
87 if (opt->find(grp) == STR_NPOS) {
88 *opt += grp;
89 return 1;
90 }
91 }
92
93 // Process next
94 return 0;
95}
96
97////////////////////////////////////////////////////////////////////////////////
98/// Constructor
99
100XrdProofGroup::XrdProofGroup(const char *n, const char *m)
101 : fName(n), fMembers(m)
102{
103 fSize = 0;
104 fPriority = -1;
105 fFraction = -1;
106 fFracEff = 0;
108}
109////////////////////////////////////////////////////////////////////////////////
110/// Destructor
111
113{
114 if (fMutex)
115 delete fMutex;
116 fMutex = 0;
117}
118
119////////////////////////////////////////////////////////////////////////////////
120/// Dump group content
121
123{
124 XPDLOC(GMGR, "Group::Print")
125
127
128 if (fName != "default") {
129 TRACE(ALL, "+++ Group: "<<fName<<", size "<<fSize<<" member(s) ("<<fMembers<<")");
130 TRACE(ALL, "+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
131 TRACE(ALL, "+++ End of Group: "<<fName);
132 } else {
133 TRACE(ALL, "+++ Group: "<<fName);
134 TRACE(ALL, "+++ Priority: "<<fPriority<<", fraction: "<<fFraction);
135 TRACE(ALL, "+++ End of Group: "<<fName);
136 }
137}
138
139////////////////////////////////////////////////////////////////////////////////
140/// Modify the active count
141
142void XrdProofGroup::Count(const char *usr, int n)
143{
144 // A username must be defined and an action required
145 if (!usr || !usr[0] || n == 0)
146 return;
147
149
150 XrdProofGroupMember *m = fActives.Find(usr);
151 if (!m) {
152 // Create a new active user
153 m = new XrdProofGroupMember(usr);
154 fActives.Add(usr, m);
155 }
156
157 // Count
158 if (m) {
159 m->Count(n);
160 // If no active sessions left, remove from active
161 if (m->Active() <= 0) {
162 fActives.Del(usr);
163 delete m;
164 }
165 }
166}
167
168////////////////////////////////////////////////////////////////////////////////
169/// Return the number of active groups (usr = 0) or the number of
170/// active sessions for user 'usr'
171
172int XrdProofGroup::Active(const char *usr)
173{
175
176 int na = 0;
177 if (!usr || !usr[0]) {
178 na = fActives.Num();
179 } else {
180 XrdProofGroupMember *m = fActives.Find(usr);
181 if (m) na = m->Active();
182 }
183 // Done
184 return na;
185}
186
187////////////////////////////////////////////////////////////////////////////////
188/// Check if 'usr' is member of this group
189
190bool XrdProofGroup::HasMember(const char *usr)
191{
193 XrdOucString u(usr); u += ",";
194 int iu = fMembers.find(u);
195 if (iu != STR_NPOS)
196 if (iu == 0 || fMembers[iu-1] == ',')
197 return 1;
198 return 0;
199}
200
201////////////////////////////////////////////////////////////////////////////////
202/// Constructor
203
205{
206 ResetIter();
207 Config(fn);
208}
209
210////////////////////////////////////////////////////////////////////////////////
211/// Apply function 'f' to the hash table of groups; 'arg' is passed to 'f'
212/// in the last argument. After applying 'f', the action depends on the
213/// return value with the following rule:
214/// < 0 - the hash table item is deleted.
215/// = 0 - the next hash table item is processed.
216/// > 0 - processing stops and the hash table item is returned.
217
219 void *), void *arg)
220{
221 return (fGroups.Num() > 0 ? fGroups.Apply(f,arg) : (XrdProofGroup *)0);
222}
223
224////////////////////////////////////////////////////////////////////////////////
225/// Return a string describing the group
226
227XrdOucString XrdProofGroupMgr::Export(const char *grp)
228{
230
231 XrdOucString msg;
232
233 if (!grp) {
234 fGroups.Apply(ExportGroup, (void *) &msg);
235 } else {
236 XrdProofGroup *g = fGroups.Find(grp);
237 ExportGroup(grp, g, (void *) &msg);
238 }
239
240 return msg;
241}
242
243////////////////////////////////////////////////////////////////////////////////
244/// Return a string describing the group
245
246void XrdProofGroupMgr::Print(const char *grp)
247{
249
250 if (!grp) {
251 fGroups.Apply(PrintGroup, 0);
252 } else {
253 XrdProofGroup *g = fGroups.Find(grp);
254 PrintGroup(grp, g, 0);
255 }
256
257 return;
258}
259
260////////////////////////////////////////////////////////////////////////////////
261/// Returns the instance of for group 'grp.
262/// Return 0 in the case the group does not exist
263
265{
266 // If the group is defined and exists, check it
267 if (grp && strlen(grp) > 0) {
269 return fGroups.Find(grp);
270 }
271 return (XrdProofGroup *)0;
272}
273
274////////////////////////////////////////////////////////////////////////////////
275/// Returns the instance of the first group to which this user belongs;
276/// if grp != 0, return the instance corresponding to group 'grp', if
277/// existing and the // user belongs to it.
278/// Return 0 in the case the user does not belong to any group or does not
279/// belong to 'grp'.
280
281XrdProofGroup *XrdProofGroupMgr::GetUserGroup(const char *usr, const char *grp)
282{
283 XrdProofGroup *g = 0;
284
285 // Check inputs
286 if (!usr || strlen(usr) <= 0)
287 return g;
288
290
291 // If the group is defined and exists, check it
292 if (grp && strlen(grp) > 0) {
293 g = fGroups.Find(grp);
294 if (g && (!strncmp(g->Name(),"default",7) || g->HasMember(usr)))
295 return g;
296 else
297 return (XrdProofGroup *)0;
298 }
299
300 // Scan the table
301 g = fGroups.Apply(CheckUser, (void *)usr);
302
303 // Assign to "default" group if nothing was found
304 return ((!g) ? fGroups.Find("default") : g);
305}
306
307////////////////////////////////////////////////////////////////////////////////
308/// Returns the instance of next group in the pseudo-iterator
309/// functionality. To scan over all the groups do the following:
310/// ResetIter();
311/// while ((g = Next())) {
312/// // ... Process group
313/// }
314/// Return 0 when there are no more groups
315
317{
318 return fGroups.Apply(AuxFunc,&fIterator);
319}
320
321////////////////////////////////////////////////////////////////////////////////
322/// (Re-)configure the group info using the file 'fn'.
323/// Return the number of active groups or -1 in case of error.
324
325int XrdProofGroupMgr::Config(const char *fn)
326{
327 XPDLOC(GMGR, "GroupMgr::Config")
328
329 if ((!fn || strlen(fn) <= 0)) {
330 if (fCfgFile.fName != fn) {
331 // This call is to reset existing info and remain with
332 // the 'default' group only
334 // Reset existing info
335 fGroups.Purge();
336 // Create "default" group
337 fGroups.Add("default", new XrdProofGroup("default"));
338 // Reset fCfgFile
339 fCfgFile.fName = "";
340 fCfgFile.fMtime = 0;
341 }
342 return fGroups.Num();
343 }
344
345 // Did the file changed ?
346 if (fCfgFile.fName != fn) {
347 fCfgFile.fName = fn;
349 fCfgFile.fMtime = 0;
350 }
351
352 // Get the modification time
353 struct stat st;
354 if (stat(fCfgFile.fName.c_str(), &st) != 0)
355 return -1;
356 TRACE(DBG, "enter: time of last modification: " << st.st_mtime);
357
358 // Nothing to do if the file did not change
359 if (st.st_mtime <= fCfgFile.fMtime) return fGroups.Num();
360
361 // Save the modification time
362 fCfgFile.fMtime = st.st_mtime;
363
364 // This part must be modified in atomic way
366
367 // Reset existing info
368 fGroups.Purge();
369
370 // Create "default" group
371 fGroups.Add("default", new XrdProofGroup("default"));
372
373 // Read now the directives (recursive processing of 'include sub-file'
374 // in here)
375 if (ParseInfoFrom(fCfgFile.fName.c_str()) != 0) {
376 TRACE(XERR, "problems parsing config file "<<fCfgFile.fName);
377 }
378
379 // Notify the content
380 Print(0);
381
382 // Return the number of active groups
383 return fGroups.Num();
384}
385
386////////////////////////////////////////////////////////////////////////////////
387/// Parse config information from the open file 'fin'. Can be called
388/// recursively following 'include sub-file' lines.
389/// Return 0 or -1 in case of error.
390
392{
393 XPDLOC(GMGR, "GroupMgr::ParseInfoFrom")
394
395 // Check input
396 if (!fn || strlen(fn) <= 0) {
397 TRACE(XERR, "file name undefined!");
398 return -1;
399 }
400
401 // Open the defined path.
402 FILE *fin = 0;
403 if (!(fin = fopen(fn, "r"))) {
404 TRACE(XERR, "cannot open file: "<<fn<<" (errno:"<<errno<<")");
405 return -1;
406 }
407
408 // Read now the directives
409 char lin[2048];
410 while (fgets(lin,sizeof(lin),fin)) {
411 // Remove trailing '\n'
412 if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
413 // Skip comments or empty lines
414 if (lin[0] == '#' || strlen(lin) <= 0) continue;
415 // Good line: parse it
416 bool gotkey = 0, gotgrp = 0;
417 XrdOucString gl(lin), tok, key, group;
418 gl.replace(" ",",");
419 int from = 0;
420 while ((from = gl.tokenize(tok, from, ',')) != -1) {
421 if (tok.length() > 0) {
422 if (!gotkey) {
423 key = tok;
424 gotkey = 1;
425 } else if (!gotgrp) {
426 group = tok;
427 gotgrp = 1;
428 break;
429 }
430 }
431 }
432 // Check consistency
433 if (!gotkey || !gotgrp) {
434 // Insufficient info
435 TRACE(DBG, "incomplete line: " << lin);
436 continue;
437 }
438
439 if (key == "include") {
440 // File to be included in the parsing
441 XrdOucString subfn = group;
442 // Expand the path
444 // Process it
445 if (ParseInfoFrom(subfn.c_str()) != 0) {
446 TRACE(XERR, "problems parsing included file "<<subfn);
447 }
448 continue;
449 }
450
451 if (key == "priorityfile") {
452 // File from which (updated) priorities are read
456 continue;
457 }
458
459 // Get linked to the group, if any
460 XrdProofGroup *g = fGroups.Find(group.c_str());
461
462 // Action depends on key
463 if (key == "group") {
464 if (!g)
465 // Create new group container
466 fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
467 while ((from = gl.tokenize(tok, from, ',')) != -1) {
468 if (tok.length() > 0)
469 // Add group member
470 g->AddMember(tok.c_str());
471 }
472 } else if (key == "property") {
473 // Property definition: format of property is
474 // property <group> <property_name> <nominal_value> [<effective_value>]
475 XrdOucString name;
476 int nom=0;
477 bool gotname = 0, gotnom = 0;
478 while ((from = gl.tokenize(tok, from, ',')) != -1) {
479 if (tok.length() > 0) {
480 if (!gotname) {
481 name = tok;
482 gotname= 1;
483 } else if (!gotnom) {
484 nom = atoi(tok.c_str());
485 gotnom = 1;
486 break;
487 }
488 }
489 }
490 if (!gotname || !gotnom) {
491 // Insufficient info
492 TRACE(DBG, "incomplete property line: " << lin);
493 continue;
494 }
495 if (!g)
496 // Create new group container
497 fGroups.Add(group.c_str(), (g = new XrdProofGroup(group.c_str())));
498 if (name == "priority")
499 g->SetPriority((float)nom);
500 if (name == "fraction")
501 g->SetFraction(nom);
502 }
503 }
504 // Close this file
505 fclose(fin);
506 // Done
507 return 0;
508}
509
510////////////////////////////////////////////////////////////////////////////////
511/// Read update priorities from the file defined at configuration time.
512/// Return 1 if the file did not change, 0 if the file has been read
513/// correctly, or -1 in case of error.
514
516{
517 XPDLOC(GMGR, "GroupMgr::ReadPriorities")
518
519 // Get the modification time
520 struct stat st;
521 if (stat(fPriorityFile.fName.c_str(), &st) != 0)
522 return -1;
523 TRACE(DBG, "time of last modification: " << st.st_mtime);
524
525 // File should be loaded only once
526 if (st.st_mtime <= fPriorityFile.fMtime) {
527 TRACE(DBG, "file unchanged since last reading - do nothing ");
528 return 1;
529 }
530
531 // Save the modification time
532 fPriorityFile.fMtime = st.st_mtime;
533
534 // Open the defined path.
535 FILE *fin = 0;
536 if (!(fin = fopen(fPriorityFile.fName.c_str(), "r"))) {
537 TRACE(XERR, "cannot open file: "<<fPriorityFile.fName<<" (errno:"<<errno<<")");
538 return -1;
539 }
540
541 // This part must be modified in atomic way
543
544 // Read now the directives
545 char lin[2048];
546 while (fgets(lin,sizeof(lin),fin)) {
547 // Remove trailing '\n'
548 if (lin[strlen(lin)-1] == '\n') lin[strlen(lin)-1] = '\0';
549 // Skip comments or empty lines
550 if (lin[0] == '#' || strlen(lin) <= 0) continue;
551 // Good line candidate: parse it
552 XrdOucString gl(lin), group, value;
553 // It must contain a '='
554 int from = 0;
555 if ((from = gl.tokenize(group, 0, '=')) == -1)
556 continue;
557 // Get linked to the group, if any
558 XrdProofGroup *g = fGroups.Find(group.c_str());
559 if (!g) {
560 TRACE(XERR, "found info for unknown group: "<<group<<" - ignoring");
561 continue;
562 }
563 gl.tokenize(value, from, '=');
564 if (value.length() <= 0) {
565 TRACE(XERR, "value missing: read line is: '"<<gl<<"'");
566 continue;
567 }
568 // Transform it in a usable value
569 if (value.find('.') == STR_NPOS)
570 value += '.';
571 // Save it
572 g->SetPriority((float)strtod(value.c_str(),0));
573 }
574
575 // Close the file
576 fclose(fin);
577
578 // Done
579 return 0;
580}
581
582////////////////////////////////////////////////////////////////////////////////
583/// Fill the global group structure
584
585static int GetGroupsInfo(const char *, XrdProofGroup *g, void *s)
586{
588
589 if (glo) {
590 if (g->Active() > 0) {
591 // Set the min/max priorities
592 if (glo->prmin == -1 || g->Priority() < glo->prmin)
593 glo->prmin = g->Priority();
594 if (glo->prmax == -1 || g->Priority() > glo->prmax)
595 glo->prmax = g->Priority();
596 // Set the draft fractions
597 if (g->Fraction() > 0) {
598 g->SetFracEff((float)(g->Fraction()));
599 glo->totfrac += (float)(g->Fraction());
600 } else {
601 glo->nofrac += 1;
602 }
603 }
604 } else {
605 // Not enough info: stop
606 return 1;
607 }
608
609 // Check next
610 return 0;
611}
612
613////////////////////////////////////////////////////////////////////////////////
614/// Check if user 'u' is memmebr of group 'grp'
615
616static int SetGroupFracEff(const char *, XrdProofGroup *g, void *s)
617{
618 XpdGroupEff_t *eff = (XpdGroupEff_t *)s;
619
620 if (eff && eff->glo) {
621 XpdGroupGlobal_t *glo = eff->glo;
622 if (g->Active() > 0) {
623 if (eff->opt == 0) {
624 float ef = g->Priority() / glo->prmin;
625 g->SetFracEff(ef);
626 } else if (eff->opt == 1) {
627 if (g->Fraction() < 0) {
628 float ef = ((100. - glo->totfrac) / glo->nofrac);
629 g->SetFracEff(ef);
630 }
631 } else if (eff->opt == 2) {
632 if (g->FracEff() < 0) {
633 // Share eff->cut (default 5%) between those with undefined fraction
634 float ef = (eff->cut / glo->nofrac);
635 g->SetFracEff(ef);
636 } else {
637 // renormalize
638 float ef = g->FracEff() * eff->norm;
639 g->SetFracEff(ef);
640 }
641 }
642 }
643 } else {
644 // Not enough info: stop
645 return 1;
646 }
647
648 // Check next
649 return 0;
650}
651
652////////////////////////////////////////////////////////////////////////////////
653/// Go through the list of active groups (those having at least a non-idle
654/// member) and determine the effective resource fraction on the base of
655/// the scheduling option and of priorities or nominal fractions.
656/// Return 0 in case of success, -1 in case of error, 1 if every group
657/// has the same priority so that the system scheduler should do the job.
658
660{
661 // Loop over groupd
662 XpdGroupGlobal_t glo = {-1., -1., 0, 0.};
663 Apply(GetGroupsInfo, &glo);
664
665 XpdGroupEff_t eff = {0, &glo, 0.5, 1.};
666 if (opri) {
667 // Set effective fractions
668 ResetIter();
669 eff.opt = 0;
670 Apply(SetGroupFracEff, &eff);
671
672 } else {
673 // In the fraction scheme we need to fill up with the remaining resources
674 // if at least one lower bound was found. And of course we need to restore
675 // unitarity, if it was broken
676
677 if (glo.totfrac < 100. && glo.nofrac > 0) {
678 eff.opt = 1;
679 Apply(SetGroupFracEff, &eff);
680 } else if (glo.totfrac > 100) {
681 // Leave 5% for unnamed or low priority groups
682 eff.opt = 2;
683 eff.norm = (glo.nofrac > 0) ? (100. - eff.cut)/glo.totfrac : 100./glo.totfrac ;
684 Apply(SetGroupFracEff, &eff);
685 }
686 }
687
688 // Done
689 return 0;
690}
#define f(i)
Definition: RSha256.hxx:104
#define g(i)
Definition: RSha256.hxx:105
#define TRACE(Flag, Args)
Definition: TGHtml.h:120
char name[80]
Definition: TGX11.cxx:109
static int CheckUser(const char *, XrdProofGroup *g, void *u)
Check if user 'u' is memmebr of group 'grp'.
static int AuxFunc(const char *, XrdProofGroup *g, void *s)
Generic function used for auxiliary purpose.
static int SetGroupFracEff(const char *, XrdProofGroup *g, void *s)
Check if user 'u' is memmebr of group 'grp'.
static int GetGroupsInfo(const char *, XrdProofGroup *g, void *s)
Fill the global group structure.
static int PrintGroup(const char *, XrdProofGroup *g, void *)
Print info describing group 'g' to stdout.
static int ExportGroup(const char *, XrdProofGroup *g, void *u)
Add a string describing group 'g' to a global string.
#define XPDLOC(d, x)
#define XrdSysMutexHelper
Definition: XrdSysToOuc.h:17
#define XrdSysRecMutex
Definition: XrdSysToOuc.h:18
XrdProofGroupMgr(const char *fn=0)
Constructor.
XrdProofGroup * Next()
Returns the instance of next group in the pseudo-iterator functionality.
XrdProofGroup * Apply(int(*f)(const char *, XrdProofGroup *, void *), void *arg)
Apply function 'f' to the hash table of groups; 'arg' is passed to 'f' in the last argument.
XrdOucString fIterator
Definition: XrdProofGroup.h:95
XrdOucHash< XrdProofGroup > fGroups
Definition: XrdProofGroup.h:96
void Print(const char *grp)
Return a string describing the group.
int Config(const char *fn)
(Re-)configure the group info using the file 'fn'.
XrdProofGroup * GetGroup(const char *grp)
Returns the instance of for group 'grp.
int ParseInfoFrom(const char *fn)
Parse config information from the open file 'fin'.
XrdOucString Export(const char *grp)
Return a string describing the group.
XrdProofdFile fCfgFile
Definition: XrdProofGroup.h:99
int SetEffectiveFractions(bool optprio)
Go through the list of active groups (those having at least a non-idle member) and determine the effe...
XrdSysRecMutex fMutex
Definition: XrdProofGroup.h:97
int ReadPriorities()
Read update priorities from the file defined at configuration time.
XrdProofGroup * GetUserGroup(const char *usr, const char *grp=0)
Returns the instance of the first group to which this user belongs; if grp != 0, return the instance ...
XrdProofdFile fPriorityFile
~XrdProofGroup()
Destructor.
XrdOucString fMembers
Definition: XrdProofGroup.h:53
int Active(const char *usr=0)
Return the number of active groups (usr = 0) or the number of active sessions for user 'usr'.
bool HasMember(const char *usr)
Check if 'usr' is member of this group.
void Count(const char *usr, int n=1)
Modify the active count.
XrdOucString fName
Definition: XrdProofGroup.h:51
XrdProofGroup(const char *n, const char *m=0)
Constructor.
XrdOucHash< XrdProofGroupMember > fActives
Definition: XrdProofGroup.h:55
XrdSysRecMutex * fMutex
Definition: XrdProofGroup.h:62
void Print()
Dump group content.
static char * Expand(char *p)
Expand path 'p' relative to: $HOME if begins with ~/ <user>'s $HOME if begins with ~<user>/ $PWD if d...
XrdOucString fName
Definition: XrdProofdAux.h:73
const Int_t n
Definition: legend1.C:16
static constexpr double s
XpdGroupGlobal_t * glo
auto * m
Definition: textangle.C:8