Skip to content

Implementation

The main business logic of the rate limiting mechanism of the EOS MGM is implemented by the following C++ macro:

vi eos/mgm/Macros.hh
...
 79 //------------------------------------------------------------------------------
 80 //! Stall Macro
 81 //------------------------------------------------------------------------------
 82 #define MAYSTALL eos::mgm::InFlightRegistration tracker_helper(gOFS->mTracker); \
 83   if (gOFS->IsStall) {                                                  \
 84     XrdOucString stallmsg="";                                           \
 85     int stalltime=0;                                                    \
 86     if (gOFS->ShouldStall(__FUNCTION__,__AccessMode__, vid, stalltime, stallmsg)) { \
 87       if (stalltime) {                                                  \
 88         return gOFS->Stall(error,stalltime, stallmsg.c_str());          \
 89       } else {                                                          \
 90         return gOFS->Emsg("maystall", error, EPERM, stallmsg.c_str(), ""); \
 91       }                                                                 \
 92     } else {                                                            \
 93       if (!tracker_helper.IsOK()) {                                     \
 94         stallmsg="track request, stall the client 5 seconds";           \
 95         stalltime = 5;                                                  \
 96         return gOFS->Stall(error,stalltime, stallmsg.c_str());          \
 97       }                                                                 \
 98     }                                                                   \
 99   }

This macro is called at strategic points throughout the EOS MGM code. For example the following code snippet calls the macro when a user has just opened a file:

vi eos/mgm/XrdMgmOfsFile.cc
...
 186 /*----------------------------------------------------------------------------*/
 187 int
 188 XrdMgmOfsFile::open(eos::common::VirtualIdentity* invid,
 189                     const char* inpath,
 190                     XrdSfsFileOpenMode open_mode,
 191                     mode_t Mode,
 192                     const XrdSecEntity* client,
 193                     const char* ininfo)
...
 349   if (ProcInterface::IsWriteAccess(path, pinfo.c_str())) {
 350     SET_ACCESSMODE_W;
 351   }
 352 
 353   MAYSTALL;
 354   MAYREDIRECT;

The MAYSTALL macro calls the ShouldStall() method. The following code snippet shows that the method stalls the current operation if it finds any rate:user:* limit rule that has been exceeded. The method does not take into account the type of the current operation. The length of the stall is 5 seconds plus a random number of seconds between 0 and 6.

vi eos/mgm/XrdMgmOfs/ShouldStall.cc
...
 31 bool
 32 XrdMgmOfs::ShouldStall(const char* function,
 33                        int __AccessMode__,
 34                        eos::common::VirtualIdentity& vid,
 35                        int& stalltime, XrdOucString& stallmsg)
 36 {
...
106       } else if (Access::gStallUserGroup) {
107         std::string usermatch = "rate:user:";
108         usermatch += vid.uid_string;
109         std::string groupmatch = "rate:group:";
110         groupmatch += vid.gid_string;
111         std::string userwildcardmatch = "rate:user:*";
...
115         for (it = Access::gStallRules.begin();
116              it != Access::gStallRules.end();
117              it++) {
118           std::string cmd = it->first.substr(it->first.rfind(":") + 1);
119           double cutoff = strtod(it->second.c_str(), 0) * 1.33;
120 
121           if ((it->first.find(userwildcardmatch) == 0)) {
122             // catch all rule = global user rate cut
123             XrdSysMutexHelper statLock(gOFS->MgmStats.mMutex);
124 
125             if (gOFS->MgmStats.StatAvgUid.count(cmd) &&
126                 gOFS->MgmStats.StatAvgUid[cmd].count(vid.uid) &&
127                 (gOFS->MgmStats.StatAvgUid[cmd][vid.uid].GetAvg5() > cutoff)) {
128         if (!stalltime) {
129     stalltime = 5;
130         }
131               smsg = Access::gStallComment[it->first];
132             }
133           } else if ((it->first.find(groupwildcardmatch) == 0)) {
...
171       if (stalltime) {
172   // add random offset between 0 and 5 to stalltime
173   int random_stall = rand() % 6;
174   stalltime += random_stall;
175 
176         stallmsg = "Attention: you are currently hold in this instance and each"
177                    " request is stalled for ";
178         stallmsg += (int) stalltime;
179         stallmsg += " seconds ... ";
180         stallmsg += smsg.c_str();
181         eos_static_info("info=\"stalling access to\" uid=%u gid=%u host=%s stall=%d",
182                         vid.uid, vid.gid, vid.host.c_str(), stalltime);
183         gOFS->MgmStats.Add("Stall", vid.uid, vid.gid, 1);
184         return true;
185       }
186     } else {