Branch: Tag:

1999-09-04

1999-09-04 22:40:45 by Francesco Chemolli <li@kinkie.it>

First useable implementation of the bandwidth throttling subsystem.

Rev: server/base_server/configuration.pike:1.206
Rev: server/base_server/fastpipe.pike:1.1
Rev: server/base_server/roxen.pike:1.322
Rev: server/base_server/slowpipe.pike:1.1
Rev: server/base_server/smartpipe.pike:1.29
Rev: server/base_server/throttler.pike:1.1
Rev: server/modules/throttling/baseline_throttling.pike:1.1
Rev: server/modules/throttling/throttling_bytype.pike:1.1
Rev: server/protocols/http.pike:1.152

1: + /* +  * by Francesco Chemolli +  * (C) 1999 Idonex AB +  * +  * Notice: this might look ugly, it's been designed to be split into +  * a "library" program plus a tiny imlpementation module +  */    -  + constant cvs_version="$Id"; +  + #include <module.h> + inherit "module"; +  + #ifdef THROTTLING_DEBUG + #undef THROTTLING_DEBUG + #define THROTTLING_DEBUG(X) perror("Throttling: "+X+"\n") + #else + #define THROTTLING_DEBUG(X) + #endif +  + #define THROW(X) throw( X+"\n" ) +  +  + mapping rules; + //format: ([pattern:({command_type,value,0|1(fix)})]) + //command_type is a string (+-*/=!), value a float + //if command_type==!, it means no throttling + array(string) rulenames; //needed to keep the rules in order. +  + //can throw if some rule could not be parsed. + void update_rules() { +  THROTTLING_DEBUG("by type: updating rules"); +  rules=([]); +  rulenames=({}); +  string line, *words, cmd; +  int lineno=0; +  foreach ( (replace(QUERY(rules),"\t"," ")/"\n"),line) { +  int fix=0; +  float val=0; +  string cmd; +  lineno++; +  if(!sizeof(line)) +  continue; +  if(line[0]=='#') +  continue; +  words=(line/" ")-({""}); +  +  if (words[1]=="nothrottle") { +  cmd="!"; +  val=0; +  } else if (sscanf(words[1],"%[+-*/=]%f",cmd,val) != 2) { +  THROW("Could not parse rule at line "+lineno); +  } +  if (!((<"+","-","*","/","=","!">)[cmd])) +  THROW("Unknown command at line "+lineno); +  if (cmd=="!" || sizeof(words)>2 ) { +  if (cmd=="!" || words[2]=="fix") //don't change order, or it bangs! +  fix=1; +  else +  THROW("Unknown keyword at line "+lineno); +  } +  rules[words[0]]=({cmd,val,fix}); +  rulenames+=({words[0]}); +  } +  THROTTLING_DEBUG(sprintf("by type: rules are:\n%O\n",rules)); + } +  + array register_module() { +  return ({ +  MODULE_FILTER, +  "Throttling: throttle by type", +  "This module will alter the throttling definitions by content type", +  0,0}); + } +  +  + string check_variable(string name, mixed value) { +  mixed err; +  switch (name) { +  case "rules": +  set(name,lower_case(value)); +  err=catch(update_rules()); +  if (err) { +  if (arrayp(err)) +  return err[0]; +  if (objectp(err)) +  return err->describe(); +  } +  return 0; +  } + } +  + void start() { +  update_rules(); + } +  + array low_find_rule(string tomatch, mapping rules) { +  THROTTLING_DEBUG("by type: got request for "+tomatch); +  string s; +  foreach(rulenames,s) { +  THROTTLING_DEBUG("by type: examining "+s); +  if (glob(s,tomatch)) { +  THROTTLING_DEBUG("by type: **matched"); +  return rules[s]; +  } +  } +  THROTTLING_DEBUG("by type: **no match"); +  return 0; + } +  + //override this for other similarly-working modules + array find_rule (mapping res, object id, mapping rules) { +  if (!res) return 0; +  return low_find_rule(res->type,rules); + } +  + void apply_rule(array rule, object id) { +  id->throttle=1; +  switch(rule[0]) { +  case "+": id->rate+=(int)rule[1];break; +  case "-": id->rate-=(int)rule[1];break; +  case "*": id->rate=(int)(id->rate*rule[1]);break; +  case "/": id->rate=(int)(id->rate/rule[1]);break; +  case "=": id->rate=(int)rule[1]; break; +  case "!": id->throttle=0; break; +  } +  if (rule[2]) +  id->misc->fixthrottle=1; + } +  + mixed filter (mapping res, object id) { +  array rule; +  if (id->misc->fixthrottle) +  return 0; +  rule=find_rule(res,id,rules); +  if (!rule) +  return 0; +  apply_rule(rule,id); + } +  +  + void create() { +  defvar("rules","","Rules",TYPE_TEXT_FIELD, + #"Throttling rules. One rule per line, whose format is:<br> + <tt>type-glob modifier [fix]</tt><br> + <tt>type-glob</tt> is matched on the Content Type header. + (i.e. <tt>image/gif</tt> or <tt>text/html</tt>).<p> + <i>modifier</i> is the altering rule. There are six possible rule types:<br> + <tt>+{number}</tt> adds <i>number</i> bytes/sec to the request<br> + <tt>-{number}</tt> subtracts <i>number</i> bytes/sec to the request<br> + <tt>*{number}</tt> multiplies the bandwidth assigned to the request +  by <i>number</i> (a floating-point number)<br> + <tt>/{number}</tt> divides the bandwidth assigned to the request +  by <i>number</i> (a floating-point number)<br> + <tt>={number}</tt> assigns the request <i>number</i> bytes/sec of +  bandwidth<br> + <tt>nothrottle</tt> asserts that the request is not to be throttled. +  It implies using <tt>fix</tt>.<p> +  The optional keyword <tt>fix</tt> will make the assigned bandwidth final. + The entries are scanned in order, and processing is stopped as soon as + a match is found.<p> + Lines starting with <tt>#</tt> are considered comments."); + }   Newline at end of file added.