]> git.ipfire.org Git - thirdparty/squid.git/blame_incremental - src/delay_pools.cc
Simplify appending SBuf to String (#2108)
[thirdparty/squid.git] / src / delay_pools.cc
... / ...
CommitLineData
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 77 Delay Pools */
10
11/**
12 \defgroup DelayPoolsInternal Delay Pools Internal
13 \ingroup DelayPoolsAPI
14 */
15
16#include "squid.h"
17
18#if USE_DELAY_POOLS
19#include "client_side_request.h"
20#include "comm/Connection.h"
21#include "CommonPool.h"
22#include "CompositePoolNode.h"
23#include "ConfigParser.h"
24#include "DelayBucket.h"
25#include "DelayId.h"
26#include "DelayPool.h"
27#include "DelayPools.h"
28#include "DelaySpec.h"
29#include "DelayTagged.h"
30#include "DelayUser.h"
31#include "DelayVector.h"
32#include "event.h"
33#include "http/Stream.h"
34#include "ip/Address.h"
35#include "MemObject.h"
36#include "mgr/Registration.h"
37#include "NullDelayId.h"
38#include "sbuf/SBuf.h"
39#include "Store.h"
40#include "StoreClient.h"
41
42/// \ingroup DelayPoolsInternal
43class Aggregate : public CompositePoolNode
44{
45 MEMPROXY_CLASS(Aggregate);
46
47public:
48 typedef RefCount<Aggregate> Pointer;
49 Aggregate();
50 ~Aggregate() override;
51 virtual DelaySpec *rate() {return &spec;}
52
53 virtual DelaySpec const *rate() const {return &spec;}
54
55 void stats(StoreEntry * sentry) override;
56 void dump(StoreEntry *entry) const override;
57 void update(int incr) override;
58 void parse() override;
59
60 DelayIdComposite::Pointer id(CompositeSelectionDetails &) override;
61
62private:
63
64 /// \ingroup DelayPoolsInternal
65 class AggregateId:public DelayIdComposite
66 {
67 MEMPROXY_CLASS(Aggregate::AggregateId);
68
69 public:
70 AggregateId (RefCount<Aggregate>);
71 int bytesWanted (int min, int max) const override;
72 void bytesIn(int qty) override;
73 void delayRead(const AsyncCallPointer &) override;
74
75 private:
76 RefCount<Aggregate> theAggregate;
77 };
78
79 friend class AggregateId;
80
81 DelayBucket theBucket;
82 DelaySpec spec;
83};
84
85/// \ingroup DelayPoolsInternal
86template <class Key, class Value>
87class VectorMap
88{
89
90public:
91 VectorMap();
92 unsigned int size() const;
93 unsigned char findKeyIndex (Key const key) const;
94 bool indexUsed (unsigned char const index) const;
95 unsigned int insert (Key const key);
96
97#define IND_MAP_SZ 256
98
99 Key key_map[IND_MAP_SZ];
100 Value values[IND_MAP_SZ];
101
102private:
103 unsigned int nextMapPosition;
104};
105
106/// \ingroup DelayPoolsInternal
107class VectorPool : public CompositePoolNode
108{
109 MEMPROXY_CLASS(VectorPool);
110
111public:
112 typedef RefCount<VectorPool> Pointer;
113 void dump(StoreEntry *entry) const override;
114 void parse() override;
115 void update(int incr) override;
116 void stats(StoreEntry * sentry) override;
117
118 DelayIdComposite::Pointer id(CompositeSelectionDetails &) override;
119 VectorMap<unsigned char, DelayBucket> buckets;
120 VectorPool();
121 ~VectorPool() override;
122
123protected:
124 bool keyAllocated (unsigned char const key) const;
125 virtual DelaySpec *rate() {return &spec;}
126
127 virtual DelaySpec const *rate() const {return &spec;}
128
129 virtual char const *label() const = 0;
130
131 virtual unsigned int makeKey(Ip::Address &src_addr) const = 0;
132
133 DelaySpec spec;
134
135 /// \ingroup DelayPoolsInternal
136 class Id:public DelayIdComposite
137 {
138 MEMPROXY_CLASS(VectorPool::Id);
139
140 public:
141 Id (RefCount<VectorPool>, int);
142 int bytesWanted (int min, int max) const override;
143 void bytesIn(int qty) override;
144
145 private:
146 RefCount<VectorPool> theVector;
147 int theIndex;
148 };
149};
150
151/// \ingroup DelayPoolsInternal
152class IndividualPool : public VectorPool
153{
154 MEMPROXY_CLASS(IndividualPool);
155
156protected:
157 char const *label() const override {return "Individual";}
158 unsigned int makeKey(Ip::Address &src_addr) const override;
159};
160
161/// \ingroup DelayPoolsInternal
162class ClassCNetPool : public VectorPool
163{
164 MEMPROXY_CLASS(ClassCNetPool);
165
166protected:
167 char const *label() const override {return "Network";}
168 unsigned int makeKey (Ip::Address &src_addr) const override;
169};
170
171/* don't use remote storage for these */
172/// \ingroup DelayPoolsInternal
173class ClassCBucket
174{
175
176public:
177 bool individualUsed (unsigned int index)const;
178 unsigned char findHostMapPosition (unsigned char const host) const;
179 bool individualAllocated (unsigned char host) const;
180 unsigned char hostPosition (DelaySpec &rate, unsigned char const host);
181 void initHostIndex (DelaySpec &rate, unsigned char index, unsigned char host);
182 void update (DelaySpec const &, int incr);
183 void stats(StoreEntry *)const;
184
185 DelayBucket net;
186 VectorMap<unsigned char, DelayBucket> individuals;
187};
188
189/// \ingroup DelayPoolsInternal
190class ClassCHostPool : public CompositePoolNode
191{
192 MEMPROXY_CLASS(ClassCHostPool);
193
194public:
195 typedef RefCount<ClassCHostPool> Pointer;
196 void dump(StoreEntry *entry) const override;
197 void parse() override;
198 void update(int incr) override;
199 void stats(StoreEntry * sentry) override;
200
201 DelayIdComposite::Pointer id(CompositeSelectionDetails &) override;
202 ClassCHostPool();
203 ~ClassCHostPool() override;
204
205protected:
206 bool keyAllocated (unsigned char const key) const;
207 virtual DelaySpec *rate() {return &spec;}
208
209 virtual DelaySpec const *rate() const {return &spec;}
210
211 virtual char const *label() const {return "Individual";}
212
213 virtual unsigned int makeKey(Ip::Address &src_addr) const;
214
215 unsigned char makeHostKey(Ip::Address &src_addr) const;
216
217 DelaySpec spec;
218 VectorMap<unsigned char, ClassCBucket> buckets;
219
220 class Id;
221
222 friend class ClassCHostPool::Id;
223
224 /// \ingroup DelayPoolsInternal
225 class Id:public DelayIdComposite
226 {
227 MEMPROXY_CLASS(ClassCHostPool::Id);
228
229 public:
230 Id (RefCount<ClassCHostPool>, unsigned char, unsigned char);
231 int bytesWanted (int min, int max) const override;
232 void bytesIn(int qty) override;
233
234 private:
235 RefCount<ClassCHostPool> theClassCHost;
236 unsigned char theNet;
237 unsigned char theHost;
238 };
239};
240
241void
242Aggregate::AggregateId::delayRead(const AsyncCall::Pointer &aRead)
243{
244 theAggregate->delayRead(aRead);
245}
246
247CommonPool *
248CommonPool::Factory(unsigned char _class, CompositePoolNode::Pointer& compositeCopy)
249{
250 CommonPool *result = new CommonPool;
251
252 switch (_class) {
253
254 case 0:
255 break;
256
257 case 1:
258 compositeCopy = new Aggregate;
259 result->typeLabel = SBuf("1");
260 break;
261
262 case 2:
263 result->typeLabel = SBuf("2");
264 {
265 DelayVector::Pointer temp = new DelayVector;
266 compositeCopy = temp.getRaw();
267 temp->push_back (new Aggregate);
268 temp->push_back(new IndividualPool);
269 }
270 break;
271
272 case 3:
273 result->typeLabel = SBuf("3");
274 {
275 DelayVector::Pointer temp = new DelayVector;
276 compositeCopy = temp.getRaw();
277 temp->push_back (new Aggregate);
278 temp->push_back (new ClassCNetPool);
279 temp->push_back (new ClassCHostPool);
280 }
281 break;
282
283 case 4:
284 result->typeLabel = SBuf("4");
285 {
286 DelayVector::Pointer temp = new DelayVector;
287 compositeCopy = temp.getRaw();
288 temp->push_back (new Aggregate);
289 temp->push_back (new ClassCNetPool);
290 temp->push_back (new ClassCHostPool);
291#if USE_AUTH
292 temp->push_back (new DelayUser);
293#endif
294 }
295 break;
296
297 case 5:
298 result->typeLabel = SBuf("5");
299 compositeCopy = new DelayTagged;
300 break;
301
302 default:
303 fatal ("unknown delay pool class");
304 return nullptr;
305 };
306
307 return result;
308}
309
310CommonPool::CommonPool()
311{}
312
313void
314ClassCBucket::update (DelaySpec const &rate, int incr)
315{
316 /* If we aren't active, don't try to update us ! */
317 assert (rate.restore_bps != -1);
318
319 for (unsigned int j = 0; j < individuals.size(); ++j)
320 individuals.values[j].update (rate, incr);
321}
322
323void
324ClassCBucket::stats(StoreEntry *sentry)const
325{
326 for (unsigned int j = 0; j < individuals.size(); ++j) {
327 assert (individualUsed (j));
328 storeAppendPrintf(sentry, " %d:",individuals.key_map[j]);
329 individuals.values[j].stats (sentry);
330 }
331}
332
333unsigned char
334ClassCBucket::findHostMapPosition (unsigned char const host) const
335{
336 return individuals.findKeyIndex(host);
337}
338
339bool
340ClassCBucket::individualUsed (unsigned int index)const
341{
342 return individuals.indexUsed(index);
343}
344
345bool
346ClassCBucket::individualAllocated (unsigned char host) const
347{
348 return individualUsed(findHostMapPosition (host));
349}
350
351unsigned char
352ClassCBucket::hostPosition (DelaySpec &rate, unsigned char const host)
353{
354 if (individualAllocated (host))
355 return findHostMapPosition(host);
356
357 assert (!individualUsed (findHostMapPosition(host)));
358
359 unsigned char result = findHostMapPosition(host);
360
361 initHostIndex (rate, result, host);
362
363 return result;
364}
365
366void
367ClassCBucket::initHostIndex (DelaySpec &rate, unsigned char index, unsigned char host)
368{
369 assert (!individualUsed(index));
370
371 unsigned char const newIndex = individuals.insert (host);
372
373 /* give the bucket a default value */
374 individuals.values[newIndex].init (rate);
375}
376
377Aggregate::Aggregate()
378{
379 theBucket.init (*rate());
380 DelayPools::registerForUpdates (this);
381}
382
383Aggregate::~Aggregate()
384{
385 DelayPools::deregisterForUpdates (this);
386}
387
388void
389Aggregate::stats(StoreEntry * sentry)
390{
391 rate()->stats (sentry, "Aggregate");
392
393 if (rate()->restore_bps == -1)
394 return;
395
396 storeAppendPrintf(sentry, "\t\tCurrent: ");
397
398 theBucket.stats(sentry);
399
400 storeAppendPrintf(sentry, "\n\n");
401}
402
403void
404Aggregate::dump(StoreEntry *entry) const
405{
406 rate()->dump (entry);
407}
408
409void
410Aggregate::update(int incr)
411{
412 theBucket.update(*rate(), incr);
413 kickReads();
414}
415
416void
417Aggregate::parse()
418{
419 rate()->parse();
420}
421
422DelayIdComposite::Pointer
423Aggregate::id(CompositeSelectionDetails &)
424{
425 if (rate()->restore_bps != -1)
426 return new AggregateId (this);
427 else
428 return new NullDelayId;
429}
430
431Aggregate::AggregateId::AggregateId(RefCount<Aggregate> anAggregate) : theAggregate(anAggregate)
432{}
433
434int
435Aggregate::AggregateId::bytesWanted (int min, int max) const
436{
437 return theAggregate->theBucket.bytesWanted(min, max);
438}
439
440void
441Aggregate::AggregateId::bytesIn(int qty)
442{
443 theAggregate->theBucket.bytesIn(qty);
444 theAggregate->kickReads();
445}
446
447DelayPool *DelayPools::delay_data = nullptr;
448time_t DelayPools::LastUpdate = 0;
449unsigned short DelayPools::pools_ (0);
450
451void
452DelayPools::RegisterWithCacheManager(void)
453{
454 Mgr::RegisterAction("delay", "Delay Pool Levels", Stats, 0, 1);
455}
456
457void
458DelayPools::Init()
459{
460 LastUpdate = getCurrentTime();
461 RegisterWithCacheManager();
462}
463
464void
465DelayPools::InitDelayData()
466{
467 if (!pools())
468 return;
469
470 DelayPools::delay_data = new DelayPool[pools()];
471
472 eventAdd("DelayPools::Update", DelayPools::Update, nullptr, 1.0, 1);
473}
474
475void
476DelayPools::FreeDelayData()
477{
478 delete[] DelayPools::delay_data;
479 pools_ = 0;
480}
481
482void
483DelayPools::Update(void *)
484{
485 // To prevent stuck transactions, stop updates only after no new transactions can
486 // register (because the pools were disabled) and the last registered transaction is gone.
487 if (!pools() && toUpdate.empty())
488 return;
489
490 eventAdd("DelayPools::Update", Update, nullptr, 1.0, 1);
491
492 int incr = squid_curtime - LastUpdate;
493
494 if (incr < 1)
495 return;
496
497 LastUpdate = squid_curtime;
498
499 std::vector<Updateable *>::iterator pos = toUpdate.begin();
500
501 while (pos != toUpdate.end()) {
502 (*pos)->update(incr);
503 ++pos;
504 }
505}
506
507void
508DelayPools::registerForUpdates(Updateable *anObject)
509{
510 /* Assume no doubles */
511 toUpdate.push_back(anObject);
512}
513
514void
515DelayPools::deregisterForUpdates (Updateable *anObject)
516{
517 std::vector<Updateable *>::iterator pos = toUpdate.begin();
518
519 while (pos != toUpdate.end() && *pos != anObject) {
520 ++pos;
521 }
522
523 if (pos != toUpdate.end()) {
524 /* move all objects down one */
525 std::vector<Updateable *>::iterator temp = pos;
526 ++pos;
527
528 while (pos != toUpdate.end()) {
529 *temp = *pos;
530 ++temp;
531 ++pos;
532 }
533
534 toUpdate.pop_back();
535 }
536}
537
538std::vector<Updateable *> DelayPools::toUpdate;
539
540void
541DelayPools::Stats(StoreEntry * sentry)
542{
543 storeAppendPrintf(sentry, "Delay pools configured: %d\n\n", DelayPools::pools());
544
545 for (unsigned short i = 0; i < DelayPools::pools(); ++i) {
546 if (DelayPools::delay_data[i].theComposite().getRaw()) {
547 storeAppendPrintf(sentry, "Pool: %d\n\tClass: " SQUIDSBUFPH "\n\n", i + 1, SQUIDSBUFPRINT(DelayPools::delay_data[i].pool->classTypeLabel()));
548 DelayPools::delay_data[i].theComposite()->stats (sentry);
549 } else
550 storeAppendPrintf(sentry, "\tMisconfigured pool.\n\n");
551 }
552}
553
554void
555DelayPools::FreePools()
556{
557 if (!DelayPools::pools())
558 return;
559
560 FreeDelayData();
561}
562
563unsigned short
564DelayPools::pools()
565{
566 return pools_;
567}
568
569void
570DelayPools::pools(unsigned short newPools)
571{
572 if (pools()) {
573 debugs(3, DBG_CRITICAL, "parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config");
574 FreePools();
575 }
576
577 pools_ = newPools;
578
579 if (pools())
580 InitDelayData();
581}
582
583template <class Key, class Value>
584VectorMap<Key,Value>::VectorMap() : nextMapPosition(0)
585{}
586
587template <class Key, class Value>
588unsigned int
589VectorMap<Key,Value>::size() const
590{
591 return nextMapPosition;
592}
593
594template <class Key, class Value>
595unsigned int
596VectorMap<Key,Value>::insert (Key const key)
597{
598 unsigned char index = findKeyIndex (key);
599 assert (!indexUsed(index));
600
601 key_map[index] = key;
602
603 ++nextMapPosition;
604
605 return index;
606}
607
608VectorPool::VectorPool()
609{
610 DelayPools::registerForUpdates (this);
611}
612
613VectorPool::~VectorPool()
614{
615 DelayPools::deregisterForUpdates (this);
616}
617
618void
619VectorPool::stats(StoreEntry * sentry)
620{
621 rate()->stats (sentry, label());
622
623 if (rate()->restore_bps == -1) {
624 storeAppendPrintf(sentry, "\n\n");
625 return;
626 }
627
628 storeAppendPrintf(sentry, "\t\tCurrent:");
629
630 for (unsigned int i = 0; i < buckets.size(); ++i) {
631 storeAppendPrintf(sentry, " %d:", buckets.key_map[i]);
632 buckets.values[i].stats(sentry);
633 }
634
635 if (!buckets.size())
636 storeAppendPrintf(sentry, " Not used yet.");
637
638 storeAppendPrintf(sentry, "\n\n");
639}
640
641void
642VectorPool::dump(StoreEntry *entry) const
643{
644 rate()->dump (entry);
645}
646
647void
648VectorPool::update(int incr)
649{
650 if (rate()->restore_bps == -1)
651 return;
652
653 for (unsigned int i = 0; i< buckets.size(); ++i)
654 buckets.values[i].update (*rate(), incr);
655}
656
657void
658VectorPool::parse()
659{
660 rate()->parse();
661}
662
663bool
664VectorPool::keyAllocated (unsigned char const key) const
665{
666 return buckets.indexUsed(buckets.findKeyIndex (key));
667}
668
669template <class Key, class Value>
670bool
671VectorMap<Key,Value>::indexUsed (unsigned char const index) const
672{
673 return index < size();
674}
675
676/** returns the used position, or the position to allocate */
677template <class Key, class Value>
678unsigned char
679VectorMap<Key,Value>::findKeyIndex (Key const key) const
680{
681 for (unsigned int index = 0; index < size(); ++index) {
682 assert(indexUsed(index));
683
684 if (key_map[index] == key)
685 return index;
686 }
687
688 /* not in map */
689 return size();
690}
691
692DelayIdComposite::Pointer
693VectorPool::id(CompositeSelectionDetails &details)
694{
695 if (rate()->restore_bps == -1)
696 return new NullDelayId;
697
698 /* non-IPv4 are not able to provide IPv4-bitmask for this pool type key. */
699 if ( !details.src_addr.isIPv4() )
700 return new NullDelayId;
701
702 unsigned int key = makeKey(details.src_addr);
703
704 if (keyAllocated(key))
705 return new Id(this, buckets.findKeyIndex(key));
706
707 unsigned char const resultIndex = buckets.insert(key);
708
709 buckets.values[resultIndex].init(*rate());
710
711 return new Id(this, resultIndex);
712}
713
714VectorPool::Id::Id(VectorPool::Pointer aPool, int anIndex) : theVector (aPool), theIndex (anIndex)
715{}
716
717int
718VectorPool::Id::bytesWanted (int min, int max) const
719{
720 return theVector->buckets.values[theIndex].bytesWanted (min, max);
721}
722
723void
724VectorPool::Id::bytesIn(int qty)
725{
726 theVector->buckets.values[theIndex].bytesIn (qty);
727}
728
729unsigned int
730IndividualPool::makeKey(Ip::Address &src_addr) const
731{
732 /* IPv4 required for this pool */
733 if ( !src_addr.isIPv4() )
734 return 1;
735
736 struct in_addr host;
737 src_addr.getInAddr(host);
738 return (ntohl(host.s_addr) & 0xff);
739}
740
741unsigned int
742ClassCNetPool::makeKey(Ip::Address &src_addr) const
743{
744 /* IPv4 required for this pool */
745 if ( !src_addr.isIPv4() )
746 return 1;
747
748 struct in_addr net;
749 src_addr.getInAddr(net);
750 return ( (ntohl(net.s_addr) >> 8) & 0xff);
751}
752
753ClassCHostPool::ClassCHostPool()
754{
755 DelayPools::registerForUpdates (this);
756}
757
758ClassCHostPool::~ClassCHostPool()
759{
760 DelayPools::deregisterForUpdates (this);
761}
762
763void
764ClassCHostPool::stats(StoreEntry * sentry)
765{
766 rate()->stats (sentry, label());
767
768 if (rate()->restore_bps == -1) {
769 storeAppendPrintf(sentry, "\n\n");
770 return;
771 }
772
773 for (unsigned int index = 0; index < buckets.size(); ++index) {
774 storeAppendPrintf(sentry, "\t\tCurrent [Network %d]:", buckets.key_map[index]);
775 buckets.values[index].stats (sentry);
776 storeAppendPrintf(sentry, "\n");
777 }
778
779 if (!buckets.size())
780 storeAppendPrintf(sentry, "\t\tCurrent [All networks]: Not used yet.\n");
781
782 storeAppendPrintf(sentry, "\n\n");
783}
784
785void
786ClassCHostPool::dump(StoreEntry *entry) const
787{
788 rate()->dump (entry);
789}
790
791void
792ClassCHostPool::update(int incr)
793{
794 if (rate()->restore_bps == -1)
795 return;
796
797 for (unsigned int i = 0; i< buckets.size(); ++i)
798 buckets.values[i].update (*rate(), incr);
799}
800
801void
802ClassCHostPool::parse()
803{
804 rate()->parse();
805}
806
807bool
808ClassCHostPool::keyAllocated (unsigned char const key) const
809{
810 return buckets.indexUsed(buckets.findKeyIndex (key));
811}
812
813unsigned char
814ClassCHostPool::makeHostKey(Ip::Address &src_addr) const
815{
816 /* IPv4 required for this pool */
817 if ( !src_addr.isIPv4() )
818 return 1;
819
820 /* Temporary bypass for IPv4-only */
821 struct in_addr host;
822 src_addr.getInAddr(host);
823 return (ntohl(host.s_addr) & 0xff);
824}
825
826unsigned int
827ClassCHostPool::makeKey(Ip::Address &src_addr) const
828{
829 /* IPv4 required for this pool */
830 if ( !src_addr.isIPv4() )
831 return 1;
832
833 struct in_addr net;
834 src_addr.getInAddr(net);
835 return ( (ntohl(net.s_addr) >> 8) & 0xff);
836}
837
838DelayIdComposite::Pointer
839ClassCHostPool::id(CompositeSelectionDetails &details)
840{
841 if (rate()->restore_bps == -1)
842 return new NullDelayId;
843
844 /* non-IPv4 are not able to provide IPv4-bitmask for this pool type key. */
845 if ( !details.src_addr.isIPv4() )
846 return new NullDelayId;
847
848 unsigned int key = makeKey (details.src_addr);
849
850 unsigned char host = makeHostKey (details.src_addr);
851
852 unsigned char hostIndex;
853
854 unsigned char netIndex;
855
856 if (keyAllocated (key))
857 netIndex = buckets.findKeyIndex(key);
858 else
859 netIndex = buckets.insert (key);
860
861 hostIndex = buckets.values[netIndex].hostPosition (*rate(), host);
862
863 return new Id (this, netIndex, hostIndex);
864}
865
866ClassCHostPool::Id::Id (ClassCHostPool::Pointer aPool, unsigned char aNet, unsigned char aHost) : theClassCHost (aPool), theNet (aNet), theHost (aHost)
867{}
868
869int
870ClassCHostPool::Id::bytesWanted (int min, int max) const
871{
872 return theClassCHost->buckets.values[theNet].individuals.values[theHost].bytesWanted (min, max);
873}
874
875void
876ClassCHostPool::Id::bytesIn(int qty)
877{
878 theClassCHost->buckets.values[theNet].individuals.values[theHost].bytesIn (qty);
879}
880
881#endif /* USE_DELAY_POOLS */
882