1 /*
2  * Copyright (C) 1996-2021 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 #include "squid.h"
12 
13 #if USE_DELAY_POOLS
14 #include "comm/Connection.h"
15 #include "DelayTagged.h"
16 #include "NullDelayId.h"
17 #include "Store.h"
18 
DelayTagged()19 DelayTagged::DelayTagged()
20 {
21     DelayPools::registerForUpdates (this);
22 }
23 
24 static Splay<DelayTaggedBucket::Pointer>::SPLAYFREE DelayTaggedFree;
25 
~DelayTagged()26 DelayTagged::~DelayTagged()
27 {
28     DelayPools::deregisterForUpdates (this);
29     buckets.destroy(DelayTaggedFree);
30 }
31 
32 static Splay<DelayTaggedBucket::Pointer>::SPLAYCMP DelayTaggedCmp;
33 
34 int
DelayTaggedCmp(DelayTaggedBucket::Pointer const & left,DelayTaggedBucket::Pointer const & right)35 DelayTaggedCmp(DelayTaggedBucket::Pointer const &left, DelayTaggedBucket::Pointer const &right)
36 {
37     /* for rate limiting, case insensitive */
38     return left->tag.caseCmp(right->tag);
39 }
40 
41 void
DelayTaggedFree(DelayTaggedBucket::Pointer &)42 DelayTaggedFree(DelayTaggedBucket::Pointer &)
43 {}
44 
45 struct DelayTaggedStatsVisitor {
46     StoreEntry *sentry;
DelayTaggedStatsVisitorDelayTaggedStatsVisitor47     explicit DelayTaggedStatsVisitor(StoreEntry *se): sentry(se) {}
operator ()DelayTaggedStatsVisitor48     void operator() (DelayTaggedBucket::Pointer const &current) {
49         current->stats(sentry);
50     }
51 };
52 
53 void
stats(StoreEntry * sentry)54 DelayTagged::stats(StoreEntry * sentry)
55 {
56     spec.stats (sentry, "Per Tag");
57 
58     if (spec.restore_bps == -1)
59         return;
60 
61     storeAppendPrintf(sentry, "\t\tCurrent: ");
62 
63     if (buckets.empty()) {
64         storeAppendPrintf (sentry, "Not used yet.\n\n");
65         return;
66     }
67 
68     DelayTaggedStatsVisitor visitor(sentry);
69     buckets.visit(visitor);
70     storeAppendPrintf(sentry, "\n\n");
71 }
72 
73 void
dump(StoreEntry * entry) const74 DelayTagged::dump(StoreEntry *entry) const
75 {
76     spec.dump(entry);
77 }
78 
79 struct DelayTaggedUpdater {
DelayTaggedUpdaterDelayTaggedUpdater80     DelayTaggedUpdater (DelaySpec &_spec, int _incr):spec(_spec),incr(_incr) {};
81 
82     DelaySpec spec;
83     int incr;
84 };
85 
86 void
DelayTaggedUpdateWalkee(DelayTaggedBucket::Pointer const & current,void * state)87 DelayTaggedUpdateWalkee(DelayTaggedBucket::Pointer const &current, void *state)
88 {
89     DelayTaggedUpdater *t = (DelayTaggedUpdater *)state;
90     /* This doesn't change the value of the DelayTaggedBucket, so is safe */
91     const_cast<DelayTaggedBucket *>(current.getRaw())->theBucket.update(t->spec, t->incr);
92 }
93 
94 struct DelayTaggedUpdateVisitor {
95     DelayTaggedUpdater *updater;
DelayTaggedUpdateVisitorDelayTaggedUpdateVisitor96     explicit DelayTaggedUpdateVisitor(DelayTaggedUpdater *u) : updater(u) {}
operator ()DelayTaggedUpdateVisitor97     void operator() (DelayTaggedBucket::Pointer const &current) {
98         const_cast<DelayTaggedBucket *>(current.getRaw())->theBucket.update(updater->spec, updater->incr);
99     }
100 };
101 
102 void
update(int incr)103 DelayTagged::update(int incr)
104 {
105     DelayTaggedUpdater updater(spec, incr);
106     DelayTaggedUpdateVisitor visitor(&updater);
107     buckets.visit(visitor);
108     kickReads();
109 }
110 
111 void
parse()112 DelayTagged::parse()
113 {
114     spec.parse();
115 }
116 
117 DelayIdComposite::Pointer
118 
id(CompositePoolNode::CompositeSelectionDetails & details)119 DelayTagged::id(CompositePoolNode::CompositeSelectionDetails &details)
120 {
121     if (!details.tag.size())
122         return new NullDelayId;
123 
124     return new Id(this, details.tag);
125 }
126 
DelayTaggedBucket(String & aTag)127 DelayTaggedBucket::DelayTaggedBucket(String &aTag) : tag (aTag)
128 {
129     debugs(77, 3, "DelayTaggedBucket::DelayTaggedBucket");
130 }
131 
~DelayTaggedBucket()132 DelayTaggedBucket::~DelayTaggedBucket()
133 {
134     debugs(77, 3, "DelayTaggedBucket::~DelayTaggedBucket");
135 }
136 
137 void
stats(StoreEntry * entry) const138 DelayTaggedBucket::stats(StoreEntry *entry) const
139 {
140     storeAppendPrintf(entry, " " SQUIDSTRINGPH ":", SQUIDSTRINGPRINT(tag));
141     theBucket.stats(entry);
142 }
143 
Id(DelayTagged::Pointer aDelayTagged,String & aTag)144 DelayTagged::Id::Id(DelayTagged::Pointer aDelayTagged, String &aTag) : theTagged(aDelayTagged)
145 {
146     theBucket = new DelayTaggedBucket(aTag);
147     DelayTaggedBucket::Pointer const *existing = theTagged->buckets.find(theBucket, DelayTaggedCmp);
148 
149     if (existing) {
150         theBucket = *existing;
151         return;
152     }
153 
154     theBucket->theBucket.init(theTagged->spec);
155     theTagged->buckets.insert (theBucket, DelayTaggedCmp);
156 }
157 
~Id()158 DelayTagged::Id::~Id()
159 {
160     debugs(77, 3, "DelayTagged::Id::~Id");
161 }
162 
163 int
bytesWanted(int min,int max) const164 DelayTagged::Id::bytesWanted (int min, int max) const
165 {
166     return theBucket->theBucket.bytesWanted(min,max);
167 }
168 
169 void
bytesIn(int qty)170 DelayTagged::Id::bytesIn(int qty)
171 {
172     theBucket->theBucket.bytesIn(qty);
173 }
174 
175 void
delayRead(DeferredRead const & aRead)176 DelayTagged::Id::delayRead(DeferredRead const &aRead)
177 {
178     theTagged->delayRead(aRead);
179 }
180 
181 #endif
182 
183