]> git.ipfire.org Git - thirdparty/squid.git/blame - src/BandwidthBucket.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / BandwidthBucket.cc
CommitLineData
b27668ec 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
b27668ec
EB
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"
675b8408 16#include "debug/Stream.h"
b27668ec
EB
17#include "fde.h"
18
19BandwidthBucket::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
30void
31BandwidthBucket::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
65bool
66BandwidthBucket::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
82void
83BandwidthBucket::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
94BandwidthBucket *
95BandwidthBucket::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