]>
Commit | Line | Data |
---|---|---|
b27668ec | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 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 | ||
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 |