]> git.ipfire.org Git - thirdparty/squid.git/blob - src/adaptation/History.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / adaptation / History.cc
1 /*
2 * Copyright (C) 1996-2019 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 #include "adaptation/Config.h"
11 #include "adaptation/History.h"
12 #include "base/TextException.h"
13 #include "Debug.h"
14 #include "globals.h"
15 #include "SquidTime.h"
16
17 /// impossible services value to identify unset theNextServices
18 const static char *TheNullServices = ",null,";
19
20 Adaptation::History::Entry::Entry(const String &serviceId, const timeval &when):
21 service(serviceId), start(when), theRptm(-1), retried(false)
22 {
23 }
24
25 Adaptation::History::Entry::Entry():
26 start(current_time), theRptm(-1), retried(false)
27 {
28 }
29
30 void Adaptation::History::Entry::stop()
31 {
32 // theRptm may already be set if the access log entry has already been made
33 (void)rptm(); // will cache result in theRptm if not set already
34 }
35
36 int Adaptation::History::Entry::rptm()
37 {
38 if (theRptm < 0)
39 theRptm = tvSubMsec(start, current_time);
40 return theRptm;
41 }
42
43 Adaptation::History::History():
44 lastMeta(hoReply),
45 allMeta(hoReply),
46 theNextServices(TheNullServices)
47 {
48 }
49
50 int Adaptation::History::recordXactStart(const String &serviceId, const timeval &when, bool retrying)
51 {
52 // the history will be empty on retries if it was enabled after the failure
53 if (retrying && !theEntries.empty())
54 theEntries.back().retried = true;
55
56 theEntries.push_back(Adaptation::History::Entry(serviceId, when));
57 return theEntries.size() - 1; // record position becomes history ID
58 }
59
60 void Adaptation::History::recordXactFinish(int hid)
61 {
62 Must(0 <= hid && hid < static_cast<int>(theEntries.size()));
63 theEntries[hid].stop();
64 }
65
66 void Adaptation::History::allLogString(const char *serviceId, SBuf &s)
67 {
68 s.clear();
69 bool prevWasRetried = false;
70 for (auto &i : theEntries) {
71 // TODO: here and below, optimize service ID comparison?
72 if (!serviceId || i.service == serviceId) {
73 if (!s.isEmpty()) // not the first logged time, must delimit
74 s.append(prevWasRetried ? '+' : ',');
75 s.appendf("%d", i.rptm());
76 // continue; we may have two identical services (e.g., for retries)
77 }
78 prevWasRetried = i.retried;
79 }
80 }
81
82 void Adaptation::History::sumLogString(const char *serviceId, SBuf &s)
83 {
84 s.clear();
85 int retriedRptm = 0; // sum of rptm times of retried transactions
86 for (auto & i : theEntries) {
87 if (i.retried) { // do not log retried xact but accumulate their time
88 retriedRptm += i.rptm();
89 } else if (!serviceId || i.service == serviceId) {
90 if (!s.isEmpty()) // not the first logged time, must delimit
91 s.append(',');
92 s.appendf("%d", retriedRptm + i.rptm());
93 // continue; we may have two identical services (e.g., for retries)
94 }
95
96 if (!i.retried)
97 retriedRptm = 0;
98 }
99
100 // the last transaction is never retried or it would not be the last
101 Must(!retriedRptm);
102 }
103
104 void Adaptation::History::updateXxRecord(const char *name, const String &value)
105 {
106 theXxName = name;
107 theXxValue = value;
108 }
109
110 bool Adaptation::History::getXxRecord(String &name, String &value) const
111 {
112 if (theXxName.size() <= 0)
113 return false;
114
115 name = theXxName;
116 value = theXxValue;
117 return true;
118 }
119
120 void Adaptation::History::updateNextServices(const String &services)
121 {
122 if (theNextServices != TheNullServices)
123 debugs(93,3, HERE << "old services: " << theNextServices);
124 debugs(93,3, HERE << "new services: " << services);
125 Must(services != TheNullServices);
126 theNextServices = services;
127 }
128
129 bool Adaptation::History::extractNextServices(String &value)
130 {
131 if (theNextServices == TheNullServices)
132 return false;
133
134 value = theNextServices;
135 theNextServices = TheNullServices; // prevents resetting the plan twice
136 return true;
137 }
138
139 void Adaptation::History::recordMeta(const HttpHeader *lm)
140 {
141 lastMeta.clean();
142 lastMeta.update(lm);
143
144 allMeta.update(lm);
145 allMeta.compact();
146 }
147
148 void
149 Adaptation::History::recordAdaptationService(SBuf &srvId)
150 {
151 theAdaptationServices.push_back(srvId);
152 }
153
154 void
155 Adaptation::History::setFutureServices(const DynamicGroupCfg &services)
156 {
157 if (!theFutureServices.empty())
158 debugs(93,3, HERE << "old future services: " << theFutureServices);
159 debugs(93,3, HERE << "new future services: " << services);
160 theFutureServices = services; // may be empty
161 }
162
163 bool Adaptation::History::extractFutureServices(DynamicGroupCfg &value)
164 {
165 if (theFutureServices.empty())
166 return false;
167
168 value = theFutureServices;
169 theFutureServices.clear();
170 return true;
171 }
172