3 * $Id: delay_pools.cc,v 1.50 2007/12/14 23:11:46 amosjeffries Exp $
5 * DEBUG: section 77 Delay Pools
6 * AUTHOR: Robert Collins <robertc@squid-cache.org>
7 * Based upon original delay pools code by
8 * David Luyer <david@luyer.net>
10 * SQUID Web Proxy Cache http://www.squid-cache.org/
11 * ----------------------------------------------------------
13 * Squid is the result of efforts by numerous individuals from
14 * the Internet community; see the CONTRIBUTORS file for full
15 * details. Many organizations have provided support for Squid's
16 * development; see the SPONSORS file for full details. Squid is
17 * Copyrighted (C) 2001 by the Regents of the University of
18 * California; see the COPYRIGHT file for full details. Squid
19 * incorporates software developed and/or copyrighted by other
20 * sources; see the CREDITS file for full details.
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
44 #include "CacheManager.h"
45 #include "DelaySpec.h"
46 #include "DelayPools.h"
48 #include "StoreClient.h"
50 #include "MemObject.h"
51 #include "client_side_request.h"
52 #include "ConfigParser.h"
55 #include "SquidString.h"
56 #include "SquidTime.h"
57 #include "CommonPool.h"
58 #include "CompositePoolNode.h"
59 #include "DelayPool.h"
60 #include "DelayVector.h"
61 #include "NullDelayId.h"
62 #include "DelayBucket.h"
63 #include "DelayUser.h"
64 #include "DelayTagged.h"
65 #include "IPAddress.h"
67 long DelayPools::MemoryUsed
= 0;
69 class Aggregate
: public CompositePoolNode
73 typedef RefCount
<Aggregate
> Pointer
;
74 void *operator new(size_t);
75 void operator delete (void *);
78 virtual DelaySpec
*rate() {return &spec
;}
80 virtual DelaySpec
const *rate() const {return &spec
;}
82 virtual void stats(StoreEntry
* sentry
);
83 virtual void dump(StoreEntry
*entry
) const;
84 virtual void update(int incr
);
87 virtual DelayIdComposite::Pointer
id(CompositeSelectionDetails
&);
91 class AggregateId
:public DelayIdComposite
95 void *operator new(size_t);
96 void operator delete (void *);
97 AggregateId (RefCount
<Aggregate
>);
98 virtual int bytesWanted (int min
, int max
) const;
99 virtual void bytesIn(int qty
);
100 virtual void delayRead(DeferredRead
const &);
103 RefCount
<Aggregate
> theAggregate
;
106 friend class AggregateId
;
108 DelayBucket theBucket
;
112 template <class Key
, class Value
>
119 unsigned int size() const;
120 unsigned char findKeyIndex (Key
const key
) const;
121 bool indexUsed (unsigned char const index
) const;
122 unsigned int insert (Key
const key
);
124 #define IND_MAP_SZ 256
126 Key key_map
[IND_MAP_SZ
];
127 Value values
[IND_MAP_SZ
];
130 unsigned int nextMapPosition
;
133 class VectorPool
: public CompositePoolNode
137 typedef RefCount
<VectorPool
> Pointer
;
138 virtual void dump(StoreEntry
*entry
) const;
139 virtual void parse();
140 virtual void update(int incr
);
141 virtual void stats(StoreEntry
* sentry
);
143 virtual DelayIdComposite::Pointer
id(CompositeSelectionDetails
&);
144 VectorMap
<unsigned char, DelayBucket
> buckets
;
149 bool keyAllocated (unsigned char const key
) const;
150 virtual DelaySpec
*rate() {return &spec
;}
152 virtual DelaySpec
const *rate() const {return &spec
;}
154 virtual char const *label() const = 0;
156 virtual unsigned int makeKey (IPAddress
&src_addr
) const = 0;
160 class Id
:public DelayIdComposite
164 void *operator new(size_t);
165 void operator delete (void *);
166 Id (RefCount
<VectorPool
>, int);
167 virtual int bytesWanted (int min
, int max
) const;
168 virtual void bytesIn(int qty
);
171 RefCount
<VectorPool
> theVector
;
176 class IndividualPool
: public VectorPool
180 void *operator new(size_t);
181 void operator delete (void *);
184 virtual char const *label() const {return "Individual";}
186 virtual unsigned int makeKey (IPAddress
&src_addr
) const;
190 class ClassCNetPool
: public VectorPool
194 void *operator new(size_t);
195 void operator delete (void *);
198 virtual char const *label() const {return "Network";}
200 virtual unsigned int makeKey (IPAddress
&src_addr
) const;
203 /* don't use remote storage for these */
209 bool individualUsed (unsigned int index
)const;
210 unsigned char findHostMapPosition (unsigned char const host
) const;
211 bool individualAllocated (unsigned char host
) const;
212 unsigned char hostPosition (DelaySpec
&rate
, unsigned char const host
);
213 void initHostIndex (DelaySpec
&rate
, unsigned char index
, unsigned char host
);
214 void update (DelaySpec
const &, int incr
);
215 void stats(StoreEntry
*)const;
218 VectorMap
<unsigned char, DelayBucket
> individuals
;
221 class ClassCHostPool
: public CompositePoolNode
225 typedef RefCount
<ClassCHostPool
> Pointer
;
226 virtual void dump(StoreEntry
*entry
) const;
227 virtual void parse();
228 virtual void update(int incr
);
229 virtual void stats(StoreEntry
* sentry
);
231 virtual DelayIdComposite::Pointer
id(CompositeSelectionDetails
&);
236 bool keyAllocated (unsigned char const key
) const;
237 virtual DelaySpec
*rate() {return &spec
;}
239 virtual DelaySpec
const *rate() const {return &spec
;}
241 virtual char const *label() const {return "Individual";}
243 virtual unsigned int makeKey (IPAddress
&src_addr
) const;
245 unsigned char makeHostKey (IPAddress
&src_addr
) const;
248 VectorMap
<unsigned char, ClassCBucket
> buckets
;
252 friend class ClassCHostPool::Id
;
254 class Id
:public DelayIdComposite
258 void *operator new(size_t);
259 void operator delete (void *);
260 Id (RefCount
<ClassCHostPool
>, unsigned char, unsigned char);
261 virtual int bytesWanted (int min
, int max
) const;
262 virtual void bytesIn(int qty
);
265 RefCount
<ClassCHostPool
> theClassCHost
;
266 unsigned char theNet
;
267 unsigned char theHost
;
272 Aggregate::AggregateId::delayRead(DeferredRead
const &aRead
)
274 theAggregate
->delayRead(aRead
);
278 CommonPool::operator new(size_t size
)
280 DelayPools::MemoryUsed
+= sizeof (CommonPool
);
281 return ::operator new (size
);
285 CommonPool::operator delete (void *address
)
287 DelayPools::MemoryUsed
-= sizeof (CommonPool
);
288 ::operator delete (address
);
292 CommonPool::Factory(unsigned char _class
, CompositePoolNode::Pointer
& compositeCopy
)
294 CommonPool
*result
= new CommonPool
;
302 compositeCopy
= new Aggregate
;
303 result
->typeLabel
= "1";
307 result
->typeLabel
= "2";
309 DelayVector::Pointer temp
= new DelayVector
;
310 compositeCopy
= temp
.getRaw();
311 temp
->push_back (new Aggregate
);
312 temp
->push_back(new IndividualPool
);
318 result
->typeLabel
= "3";
320 DelayVector::Pointer temp
= new DelayVector
;
321 compositeCopy
= temp
.getRaw();
322 temp
->push_back (new Aggregate
);
323 temp
->push_back (new ClassCNetPool
);
324 temp
->push_back (new ClassCHostPool
);
330 result
->typeLabel
= "4";
332 DelayVector::Pointer temp
= new DelayVector
;
333 compositeCopy
= temp
.getRaw();
334 temp
->push_back (new Aggregate
);
335 temp
->push_back (new ClassCNetPool
);
336 temp
->push_back (new ClassCHostPool
);
337 temp
->push_back (new DelayUser
);
343 result
->typeLabel
= "5";
344 compositeCopy
= new DelayTagged
;
348 fatal ("unknown delay pool class");
355 CommonPool::CommonPool()
359 ClassCBucket::update (DelaySpec
const &rate
, int incr
)
361 /* If we aren't active, don't try to update us ! */
362 assert (rate
.restore_bps
!= -1);
364 for (unsigned char j
= 0; j
< individuals
.size(); ++j
)
365 individuals
.values
[j
].update (rate
, incr
);
369 ClassCBucket::stats(StoreEntry
*sentry
)const
371 for (unsigned int j
= 0; j
< individuals
.size(); ++j
) {
372 assert (individualUsed (j
));
373 storeAppendPrintf(sentry
, " %d:",individuals
.key_map
[j
]);
374 individuals
.values
[j
].stats (sentry
);
379 ClassCBucket::findHostMapPosition (unsigned char const host
) const
381 return individuals
.findKeyIndex(host
);
385 ClassCBucket::individualUsed (unsigned int index
)const
387 return individuals
.indexUsed(index
);
391 ClassCBucket::individualAllocated (unsigned char host
) const
393 return individualUsed(findHostMapPosition (host
));
397 ClassCBucket::hostPosition (DelaySpec
&rate
, unsigned char const host
)
399 if (individualAllocated (host
))
400 return findHostMapPosition(host
);
402 assert (!individualUsed (findHostMapPosition(host
)));
404 unsigned char result
= findHostMapPosition(host
);
406 initHostIndex (rate
, result
, host
);
412 ClassCBucket::initHostIndex (DelaySpec
&rate
, unsigned char index
, unsigned char host
)
414 assert (!individualUsed(index
));
416 unsigned char const newIndex
= individuals
.insert (host
);
418 /* give the bucket a default value */
419 individuals
.values
[newIndex
].init (rate
);
423 CompositePoolNode::operator new(size_t size
)
425 DelayPools::MemoryUsed
+= sizeof (CompositePoolNode
);
426 return ::operator new (size
);
430 CompositePoolNode::operator delete (void *address
)
432 DelayPools::MemoryUsed
-= sizeof (CompositePoolNode
);
433 ::operator delete (address
);
437 Aggregate::operator new(size_t size
)
439 DelayPools::MemoryUsed
+= sizeof (Aggregate
);
440 return ::operator new (size
);
444 Aggregate::operator delete (void *address
)
446 DelayPools::MemoryUsed
-= sizeof (Aggregate
);
447 ::operator delete (address
);
450 Aggregate::Aggregate()
452 theBucket
.init (*rate());
453 DelayPools::registerForUpdates (this);
456 Aggregate::~Aggregate()
458 DelayPools::deregisterForUpdates (this);
462 Aggregate::stats(StoreEntry
* sentry
)
464 rate()->stats (sentry
, "Aggregate");
466 if (rate()->restore_bps
== -1)
469 storeAppendPrintf(sentry
, "\t\tCurrent: ");
471 theBucket
.stats(sentry
);
473 storeAppendPrintf(sentry
, "\n\n");
477 Aggregate::dump(StoreEntry
*entry
) const
479 rate()->dump (entry
);
483 Aggregate::update(int incr
)
485 theBucket
.update(*rate(), incr
);
495 DelayIdComposite::Pointer
497 Aggregate::id(CompositeSelectionDetails
&details
)
499 if (rate()->restore_bps
!= -1)
500 return new AggregateId (this);
502 return new NullDelayId
;
506 Aggregate::AggregateId::operator new(size_t size
)
508 DelayPools::MemoryUsed
+= sizeof (AggregateId
);
509 return ::operator new (size
);
513 Aggregate::AggregateId::operator delete (void *address
)
515 DelayPools::MemoryUsed
-= sizeof (AggregateId
);
516 ::operator delete (address
);
519 Aggregate::AggregateId::AggregateId(RefCount
<Aggregate
> anAggregate
) : theAggregate(anAggregate
)
523 Aggregate::AggregateId::bytesWanted (int min
, int max
) const
525 return theAggregate
->theBucket
.bytesWanted(min
, max
);
529 Aggregate::AggregateId::bytesIn(int qty
)
531 theAggregate
->theBucket
.bytesIn(qty
);
532 theAggregate
->kickReads();
535 DelayPool
*DelayPools::delay_data
= NULL
;
536 time_t DelayPools::LastUpdate
= 0;
537 unsigned short DelayPools::pools_ (0);
542 LastUpdate
= getCurrentTime();
546 DelayPools::RegisterWithCacheManager(CacheManager
& manager
)
548 manager
.registerAction("delay", "Delay Pool Levels", Stats
, 0, 1);
552 DelayPools::InitDelayData()
557 DelayPools::delay_data
= new DelayPool
[pools()];
559 DelayPools::MemoryUsed
+= pools() * sizeof(DelayPool
);
561 eventAdd("DelayPools::Update", DelayPools::Update
, NULL
, 1.0, 1);
565 DelayPools::FreeDelayData()
567 eventDelete(DelayPools::Update
, NULL
);
568 delete[] DelayPools::delay_data
;
569 DelayPools::MemoryUsed
-= pools() * sizeof(*DelayPools::delay_data
);
574 DelayPools::Update(void *unused
)
579 eventAdd("DelayPools::Update", Update
, NULL
, 1.0, 1);
581 int incr
= squid_curtime
- LastUpdate
;
586 LastUpdate
= squid_curtime
;
588 Vector
<Updateable
*>::iterator pos
= toUpdate
.begin();
590 while (pos
!= toUpdate
.end()) {
591 (*pos
)->update(incr
);
597 DelayPools::registerForUpdates(Updateable
*anObject
)
599 /* Assume no doubles */
600 toUpdate
.push_back(anObject
);
604 DelayPools::deregisterForUpdates (Updateable
*anObject
)
606 Vector
<Updateable
*>::iterator pos
= toUpdate
.begin();
608 while (pos
!= toUpdate
.end() && *pos
!= anObject
) {
612 if (pos
!= toUpdate
.end()) {
613 /* move all objects down one */
614 Vector
<Updateable
*>::iterator temp
= pos
;
617 while (pos
!= toUpdate
.end()) {
627 Vector
<Updateable
*> DelayPools::toUpdate
;
630 DelayPools::Stats(StoreEntry
* sentry
)
634 storeAppendPrintf(sentry
, "Delay pools configured: %d\n\n", DelayPools::pools());
636 for (i
= 0; i
< DelayPools::pools(); ++i
) {
637 if (DelayPools::delay_data
[i
].theComposite().getRaw()) {
638 storeAppendPrintf(sentry
, "Pool: %d\n\tClass: %s\n\n", i
+ 1, DelayPools::delay_data
[i
].pool
->theClassTypeLabel());
639 DelayPools::delay_data
[i
].theComposite()->stats (sentry
);
641 storeAppendPrintf(sentry
, "\tMisconfigured pool.\n\n");
644 storeAppendPrintf(sentry
, "Memory Used: %d bytes\n", (int) DelayPools::MemoryUsed
);
648 DelayPools::FreePools()
650 if (!DelayPools::pools())
663 DelayPools::pools (u_short newPools
)
666 debugs(3, 0, "parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config");
676 template <class Key
, class Value
>
677 VectorMap
<Key
,Value
>::VectorMap() : nextMapPosition(0)
680 template <class Key
, class Value
>
682 VectorMap
<Key
,Value
>::size() const
684 return nextMapPosition
;
687 template <class Key
, class Value
>
689 VectorMap
<Key
,Value
>::insert (Key
const key
)
691 unsigned char index
= findKeyIndex (key
);
692 assert (!indexUsed(index
));
694 key_map
[index
] = key
;
702 IndividualPool::operator new(size_t size
)
704 DelayPools::MemoryUsed
+= sizeof (IndividualPool
);
705 return ::operator new (size
);
709 IndividualPool::operator delete (void *address
)
711 DelayPools::MemoryUsed
-= sizeof (IndividualPool
);
712 ::operator delete (address
);
715 VectorPool::VectorPool()
717 DelayPools::registerForUpdates (this);
720 VectorPool::~VectorPool()
722 DelayPools::deregisterForUpdates (this);
726 VectorPool::stats(StoreEntry
* sentry
)
728 rate()->stats (sentry
, label());
730 if (rate()->restore_bps
== -1) {
731 storeAppendPrintf(sentry
, "\n\n");
735 storeAppendPrintf(sentry
, "\t\tCurrent:");
737 for (unsigned int i
= 0; i
< buckets
.size(); i
++) {
738 storeAppendPrintf(sentry
, " %d:", buckets
.key_map
[i
]);
739 buckets
.values
[i
].stats(sentry
);
743 storeAppendPrintf(sentry
, " Not used yet.");
745 storeAppendPrintf(sentry
, "\n\n");
749 VectorPool::dump(StoreEntry
*entry
) const
751 rate()->dump (entry
);
755 VectorPool::update(int incr
)
757 if (rate()->restore_bps
== -1)
760 for (unsigned int i
= 0; i
< buckets
.size(); ++i
)
761 buckets
.values
[i
].update (*rate(), incr
);
771 VectorPool::keyAllocated (unsigned char const key
) const
773 return buckets
.indexUsed(buckets
.findKeyIndex (key
));
776 template <class Key
, class Value
>
778 VectorMap
<Key
,Value
>::indexUsed (unsigned char const index
) const
780 return index
< size();
783 /* returns the used position, or the position to allocate */
784 template <class Key
, class Value
>
786 VectorMap
<Key
,Value
>::findKeyIndex (Key
const key
) const
788 for (unsigned int index
= 0; index
< size(); ++index
) {
789 assert (indexUsed (index
));
791 if (key_map
[index
] == key
)
799 DelayIdComposite::Pointer
801 VectorPool::id(CompositeSelectionDetails
&details
)
803 if (rate()->restore_bps
== -1)
804 return new NullDelayId
;
806 unsigned int key
= makeKey (details
.src_addr
);
808 if (keyAllocated (key
))
809 return new Id (this, buckets
.findKeyIndex(key
));
811 unsigned char const resultIndex
= buckets
.insert(key
);
813 buckets
.values
[resultIndex
].init (*rate());
815 return new Id(this, resultIndex
);
819 VectorPool::Id::operator new(size_t size
)
821 DelayPools::MemoryUsed
+= sizeof (Id
);
822 return ::operator new (size
);
826 VectorPool::Id::operator delete (void *address
)
828 DelayPools::MemoryUsed
-= sizeof (Id
);
829 ::operator delete (address
);
832 VectorPool::Id::Id (VectorPool::Pointer aPool
, int anIndex
) : theVector (aPool
), theIndex (anIndex
)
836 VectorPool::Id::bytesWanted (int min
, int max
) const
838 return theVector
->buckets
.values
[theIndex
].bytesWanted (min
, max
);
842 VectorPool::Id::bytesIn(int qty
)
844 theVector
->buckets
.values
[theIndex
].bytesIn (qty
);
848 IndividualPool::makeKey (IPAddress
&src_addr
) const
850 /* FIXME INET6 : IPv6 requires a 64-128 bit result from this function */
851 if( !src_addr
.IsIPv4() )
854 /* Temporary bypass for IPv4-only */
856 src_addr
.GetInAddr(host
);
857 return (ntohl(host
.s_addr
) & 0xff);
861 ClassCNetPool::operator new(size_t size
)
863 DelayPools::MemoryUsed
+= sizeof (ClassCNetPool
);
864 return ::operator new (size
);
868 ClassCNetPool::operator delete (void *address
)
870 DelayPools::MemoryUsed
-= sizeof (ClassCNetPool
);
871 ::operator delete (address
);
875 ClassCNetPool::makeKey (IPAddress
&src_addr
) const
877 /* FIXME INET6 : IPv6 requires a 64-128 bit result from this function */
878 if( !src_addr
.IsIPv4() )
881 /* Temporary bypass for IPv4-only */
883 src_addr
.GetInAddr(net
);
884 return ( (ntohl(net
.s_addr
) >> 8) & 0xff);
888 ClassCHostPool::ClassCHostPool()
890 DelayPools::registerForUpdates (this);
893 ClassCHostPool::~ClassCHostPool()
895 DelayPools::deregisterForUpdates (this);
899 ClassCHostPool::stats(StoreEntry
* sentry
)
901 rate()->stats (sentry
, label());
903 if (rate()->restore_bps
== -1) {
904 storeAppendPrintf(sentry
, "\n\n");
908 for (unsigned int index
= 0; index
< buckets
.size(); ++index
) {
909 storeAppendPrintf(sentry
, "\t\tCurrent [Network %d]:", buckets
.key_map
[index
]);
910 buckets
.values
[index
].stats (sentry
);
911 storeAppendPrintf(sentry
, "\n");
915 storeAppendPrintf(sentry
, "\t\tCurrent [All networks]: Not used yet.\n");
917 storeAppendPrintf(sentry
, "\n\n");
921 ClassCHostPool::dump(StoreEntry
*entry
) const
923 rate()->dump (entry
);
927 ClassCHostPool::update(int incr
)
929 if (rate()->restore_bps
== -1)
932 for (unsigned int i
= 0; i
< buckets
.size(); ++i
)
933 buckets
.values
[i
].update (*rate(), incr
);
937 ClassCHostPool::parse()
943 ClassCHostPool::keyAllocated (unsigned char const key
) const
945 return buckets
.indexUsed(buckets
.findKeyIndex (key
));
949 ClassCHostPool::makeHostKey (IPAddress
&src_addr
) const
951 /* FIXME INET6 : IPv6 requires a 64-128 bit result from this function */
952 if( !src_addr
.IsIPv4() )
955 /* Temporary bypass for IPv4-only */
957 src_addr
.GetInAddr(host
);
958 return (ntohl(host
.s_addr
) & 0xff);
962 ClassCHostPool::makeKey (IPAddress
&src_addr
) const
964 /* FIXME INET6 : IPv6 requires a 64-128 bit result from this function */
965 if( !src_addr
.IsIPv4() )
968 /* Temporary bypass for IPv4-only */
970 src_addr
.GetInAddr(net
);
971 return ( (ntohl(net
.s_addr
) >> 8) & 0xff);
974 DelayIdComposite::Pointer
976 ClassCHostPool::id(CompositeSelectionDetails
&details
)
978 if (rate()->restore_bps
== -1)
979 return new NullDelayId
;
981 unsigned int key
= makeKey (details
.src_addr
);
983 unsigned char host
= makeHostKey (details
.src_addr
);
985 unsigned char hostIndex
;
987 unsigned char netIndex
;
989 if (keyAllocated (key
))
990 netIndex
= buckets
.findKeyIndex(key
);
992 netIndex
= buckets
.insert (key
);
994 hostIndex
= buckets
.values
[netIndex
].hostPosition (*rate(), host
);
996 return new Id (this, netIndex
, hostIndex
);
1000 ClassCHostPool::Id::operator new(size_t size
)
1002 DelayPools::MemoryUsed
+= sizeof (Id
);
1003 return ::operator new (size
);
1007 ClassCHostPool::Id::operator delete (void *address
)
1009 DelayPools::MemoryUsed
-= sizeof (Id
);
1010 ::operator delete (address
);
1013 ClassCHostPool::Id::Id (ClassCHostPool::Pointer aPool
, unsigned char aNet
, unsigned char aHost
) : theClassCHost (aPool
), theNet (aNet
), theHost (aHost
)
1017 ClassCHostPool::Id::bytesWanted (int min
, int max
) const
1019 return theClassCHost
->buckets
.values
[theNet
].individuals
.values
[theHost
].bytesWanted (min
, max
);
1023 ClassCHostPool::Id::bytesIn(int qty
)
1025 theClassCHost
->buckets
.values
[theNet
].individuals
.values
[theHost
].bytesIn (qty
);