]> git.ipfire.org Git - thirdparty/squid.git/blob - src/BandwidthBucket.cc
CI: Remove unnecessary test-functionality test wrappers (#1393)
[thirdparty/squid.git] / src / BandwidthBucket.cc
1 /*
2 * Copyright (C) 1996-2023 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 #include "squid.h"
10
11 #if USE_DELAY_POOLS
12
13 #include "BandwidthBucket.h"
14 #include "ClientInfo.h"
15 #include "comm/Connection.h"
16 #include "debug/Stream.h"
17 #include "fde.h"
18
19 BandwidthBucket::BandwidthBucket(const int speed, const int initialLevelPercent, const double sizeLimit) :
20 bucketLevel( sizeLimit * (initialLevelPercent / 100.0)),
21 selectWaiting(false),
22 writeSpeedLimit(speed),
23 bucketSizeLimit(sizeLimit)
24 {
25 getCurrentTime();
26 /* put current time to have something sensible here */
27 prevTime = current_dtime;
28 }
29
30 void
31 BandwidthBucket::refillBucket()
32 {
33 if (noLimit())
34 return;
35 // all these times are in seconds, with double precision
36 const double currTime = current_dtime;
37 const double timePassed = currTime - prevTime;
38
39 // Calculate allowance for the time passed. Use double to avoid
40 // accumulating rounding errors for small intervals. For example, always
41 // adding 1 byte instead of 1.4 results in 29% bandwidth allocation error.
42 const double gain = timePassed * writeSpeedLimit;
43
44 // to further combat error accumulation during micro updates,
45 // quit before updating time if we cannot add at least one byte
46 if (gain < 1.0)
47 return;
48
49 prevTime = currTime;
50
51 // for "first" connections, drain initial fat before refilling but keep
52 // updating prevTime to avoid bursts after the fat is gone
53 if (bucketLevel > bucketSizeLimit) {
54 debugs(77, 4, "not refilling while draining initial fat");
55 return;
56 }
57
58 bucketLevel += gain;
59
60 // obey quota limits
61 if (bucketLevel > bucketSizeLimit)
62 bucketLevel = bucketSizeLimit;
63 }
64
65 bool
66 BandwidthBucket::applyQuota(int &nleft, Comm::IoCallback *state)
67 {
68 const int q = quota();
69 if (!q)
70 return false;
71 else if (q < 0)
72 return true;
73 const int nleft_corrected = min(nleft, q);
74 if (nleft != nleft_corrected) {
75 debugs(77, 5, state->conn << " writes only " <<
76 nleft_corrected << " out of " << nleft);
77 nleft = nleft_corrected;
78 }
79 return true;
80 }
81
82 void
83 BandwidthBucket::reduceBucket(const int len)
84 {
85 if (len <= 0 || noLimit())
86 return;
87 bucketLevel -= len;
88 if (bucketLevel < 0.0) {
89 debugs(77, DBG_IMPORTANT, "drained too much"); // should not happen
90 bucketLevel = 0;
91 }
92 }
93
94 BandwidthBucket *
95 BandwidthBucket::SelectBucket(fde *f)
96 {
97 BandwidthBucket *bucket = f->writeQuotaHandler.getRaw();
98 if (!bucket) {
99 ClientInfo *clientInfo = f->clientInfo;
100 if (clientInfo && clientInfo->writeLimitingActive)
101 bucket = clientInfo;
102 }
103 return bucket;
104 }
105
106 #endif /* USE_DELAY_POOLS */
107