00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "TokenBucket.h"
00010
00011 #include <sys/time.h>
00012 #include <stdlib.h>
00013 #include <unistd.h>
00014
00015 using namespace sella::algo;
00016
00017 TokenBucket::TokenBucket(const TokenBucket & chain, double limit) throw () :
00018 chain(std::make_shared<TokenBucket>(chain)),
00019
00020 stamp(0),
00021
00022 limit(limit),
00023 value(0.0)
00024 { }
00025
00026 TokenBucket::TokenBucket(double limit) throw () :
00027 chain(),
00028
00029 stamp(0),
00030
00031 limit(limit),
00032 value(0.0)
00033 { }
00034
00035 bool TokenBucket::sub(double value, bool blocking) throw () {
00036 struct timeval stamp;
00037 uint64_t usecs;
00038
00039 retry:
00040 if (this->chain.get() != NULL) {
00041 if (this->chain->sub(value, blocking) == false) {
00042 return false;
00043 }
00044 }
00045
00046 gettimeofday(&stamp, NULL);
00047 usecs = (stamp.tv_sec * 1000000) + stamp.tv_usec;
00048
00049 if ((this->value += ((usecs - this->stamp) * this->limit) / 1000000) > this->limit) {
00050 this->value = this->limit;
00051 }
00052 this->stamp = usecs;
00053
00054 if (this->value > 0.0) {
00055 this->value -= value;
00056
00057 return true;
00058 }
00059
00060 if (this->chain.get() != NULL) {
00061 this->chain->add(value);
00062 }
00063
00064 if (blocking) {
00065 usleep((0.0 - value) / this->limit * 1000000);
00066 goto retry;
00067 }
00068 return false;
00069 }
00070
00071 bool TokenBucket::add(double value) throw () {
00072 if ((this->value += value) > this->limit) {
00073 this->value = this->limit;
00074 }
00075 return true;
00076 }
00077
00078
00079
00080