Blame src/RateLimit.cc

Packit Service a2489d
/*
Packit Service a2489d
 * lftp - file transfer program
Packit Service a2489d
 *
Packit Service a2489d
 * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
Packit Service a2489d
 *
Packit Service a2489d
 * This program is free software; you can redistribute it and/or modify
Packit Service a2489d
 * it under the terms of the GNU General Public License as published by
Packit Service a2489d
 * the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
 * (at your option) any later version.
Packit Service a2489d
 *
Packit Service a2489d
 * This program is distributed in the hope that it will be useful,
Packit Service a2489d
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
 * GNU General Public License for more details.
Packit Service a2489d
 *
Packit Service a2489d
 * You should have received a copy of the GNU General Public License
Packit Service a2489d
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a2489d
 */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
#include "RateLimit.h"
Packit Service a2489d
#include "ResMgr.h"
Packit Service a2489d
#include "SMTask.h"
Packit Service a2489d
Packit Service a2489d
xmap_p<RateLimit> *RateLimit::total;
Packit Service a2489d
Packit Service a2489d
void RateLimit::AddXfer(int add)
Packit Service a2489d
{
Packit Service a2489d
   xfer_number+=add;
Packit Service a2489d
   assert(xfer_number>=0);
Packit Service a2489d
   if(parent)
Packit Service a2489d
      parent->AddXfer(add);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void RateLimit::init(level_e lvl,const char *c)
Packit Service a2489d
{
Packit Service a2489d
   level=lvl;
Packit Service a2489d
   xfer_number=(level==PER_CONN?1:0);
Packit Service a2489d
   parent=0;
Packit Service a2489d
   Reconfig(0,c);
Packit Service a2489d
Packit Service a2489d
   if(level==TOTAL) // has no parent
Packit Service a2489d
      return;
Packit Service a2489d
Packit Service a2489d
   level_e parent_level=level_e(level+1);
Packit Service a2489d
   if(parent_level==TOTAL)
Packit Service a2489d
      c=""; // no closure on top level
Packit Service a2489d
   xstring parent_key(c);
Packit Service a2489d
Packit Service a2489d
   if(!total)
Packit Service a2489d
      total=new xmap_p<RateLimit>();
Packit Service a2489d
   if(total->exists(parent_key)) {
Packit Service a2489d
      parent=total->lookup(parent_key);
Packit Service a2489d
      if(parent->xfer_number==0)
Packit Service a2489d
	 parent->Reconfig(0,c); // it was not used for a white, refresh config
Packit Service a2489d
   } else {
Packit Service a2489d
      parent=new RateLimit(parent_level,c);
Packit Service a2489d
      total->add(parent_key,parent);
Packit Service a2489d
   }
Packit Service a2489d
   parent->AddXfer(xfer_number);
Packit Service a2489d
}
Packit Service a2489d
RateLimit::~RateLimit()
Packit Service a2489d
{
Packit Service a2489d
   if(parent && xfer_number)
Packit Service a2489d
      parent->AddXfer(-xfer_number);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#define LARGE 0x10000000
Packit Service a2489d
#define DEFAULT_MAX_COEFF 2
Packit Service a2489d
void RateLimit::BytesPool::AdjustTime()
Packit Service a2489d
{
Packit Service a2489d
   double dif=TimeDiff(SMTask::now,t);
Packit Service a2489d
Packit Service a2489d
   if(dif>0)
Packit Service a2489d
   {
Packit Service a2489d
      // prevent overflow
Packit Service a2489d
      if((LARGE-pool)/dif < rate)
Packit Service a2489d
	 pool = pool_max;
Packit Service a2489d
      else
Packit Service a2489d
	 pool += int(dif*rate+0.5);
Packit Service a2489d
Packit Service a2489d
      if(pool>pool_max)
Packit Service a2489d
	 pool=pool_max;
Packit Service a2489d
Packit Service a2489d
      t=SMTask::now;
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int RateLimit::BytesAllowed(dir_t dir)
Packit Service a2489d
{
Packit Service a2489d
   int parent_allowed = parent?parent->BytesAllowed(dir):LARGE;
Packit Service a2489d
Packit Service a2489d
   if(pool[dir].rate==0) // unlimited
Packit Service a2489d
      return parent_allowed;
Packit Service a2489d
Packit Service a2489d
   pool[dir].AdjustTime();
Packit Service a2489d
Packit Service a2489d
   int allowed = pool[dir].pool/xfer_number;
Packit Service a2489d
   if(allowed>parent_allowed)
Packit Service a2489d
      allowed=parent_allowed;
Packit Service a2489d
Packit Service a2489d
   return allowed;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool RateLimit::Relaxed(dir_t dir)
Packit Service a2489d
{
Packit Service a2489d
   bool parent_relaxed = parent?parent->Relaxed(dir):true;
Packit Service a2489d
Packit Service a2489d
   if(pool[dir].rate==0) // unlimited
Packit Service a2489d
      return parent_relaxed;
Packit Service a2489d
Packit Service a2489d
   pool[dir].AdjustTime();
Packit Service a2489d
Packit Service a2489d
   if(pool[dir].rate>0 && pool[dir].pool < pool[dir].pool_max/2)
Packit Service a2489d
      return false;
Packit Service a2489d
   return parent_relaxed;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void RateLimit::BytesPool::Used(int bytes)
Packit Service a2489d
{
Packit Service a2489d
   if(pool
Packit Service a2489d
      pool=0;
Packit Service a2489d
   else
Packit Service a2489d
      pool-=bytes;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void RateLimit::BytesUsed(int bytes,dir_t dir)
Packit Service a2489d
{
Packit Service a2489d
   if(parent)
Packit Service a2489d
      parent->BytesUsed(bytes,dir);
Packit Service a2489d
   pool[dir].Used(bytes);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void RateLimit::Reset()
Packit Service a2489d
{
Packit Service a2489d
   pool[GET].Reset();
Packit Service a2489d
   pool[PUT].Reset();
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void RateLimit::BytesPool::Reset()
Packit Service a2489d
{
Packit Service a2489d
   pool=rate;
Packit Service a2489d
   t=SMTask::now;
Packit Service a2489d
}
Packit Service a2489d
void RateLimit::Reconfig(const char *name,const char *c)
Packit Service a2489d
{
Packit Service a2489d
   if(name && strncmp(name,"net:limit-",10))
Packit Service a2489d
      return; // not relevant
Packit Service a2489d
Packit Service a2489d
   bool config_total=(!name || !strncmp(name,"net:limit-total-",16));
Packit Service a2489d
Packit Service a2489d
   const char *setting_rate="net:limit-rate";
Packit Service a2489d
   const char *setting_max="net:limit-max";
Packit Service a2489d
Packit Service a2489d
   if(level>PER_CONN)
Packit Service a2489d
   {
Packit Service a2489d
      if(!config_total)
Packit Service a2489d
	 return; // not relevant
Packit Service a2489d
      if(level==TOTAL)
Packit Service a2489d
	 c=0; // aggregates everything
Packit Service a2489d
Packit Service a2489d
      setting_rate="net:limit-total-rate";
Packit Service a2489d
      setting_max="net:limit-total-max";
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   ResMgr::Query(setting_rate,c).ToNumberPair(pool[GET].rate,pool[PUT].rate);
Packit Service a2489d
   ResMgr::Query(setting_max,c).ToNumberPair(pool[GET].pool_max,pool[PUT].pool_max);
Packit Service a2489d
Packit Service a2489d
   if(pool[GET].pool_max==0)
Packit Service a2489d
      pool[GET].pool_max=pool[GET].rate*DEFAULT_MAX_COEFF;
Packit Service a2489d
   if(pool[PUT].pool_max==0)
Packit Service a2489d
      pool[PUT].pool_max=pool[PUT].rate*DEFAULT_MAX_COEFF;
Packit Service a2489d
   Reset();
Packit Service a2489d
Packit Service a2489d
   if(config_total && parent)
Packit Service a2489d
      parent->Reconfig(name,c);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int RateLimit::LimitBufferSize(int size,dir_t d) const
Packit Service a2489d
{
Packit Service a2489d
   if(pool[d].rate!=0 && size>pool[d].pool_max)
Packit Service a2489d
      size=pool[d].pool_max;
Packit Service a2489d
   return size;
Packit Service a2489d
}
Packit Service a2489d
void RateLimit::SetBufferSize(IOBuffer *buf,int size) const
Packit Service a2489d
{
Packit Service a2489d
   dir_t d = (buf->GetDirection()==buf->GET ? GET : PUT);
Packit Service a2489d
   buf->SetMaxBuffered(LimitBufferSize(size,d));
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void RateLimit::ClassCleanup()
Packit Service a2489d
{
Packit Service a2489d
   if(!total)
Packit Service a2489d
      return;
Packit Service a2489d
   for(RateLimit *t=total->each_begin(); t; t=total->each_next())
Packit Service a2489d
      t->parent=0;
Packit Service a2489d
   delete total; total=0;
Packit Service a2489d
}