Blame src/RateLimit.cc

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