1 /* Copyright (C) 2014 InfiniDB, Inc.
2 Copyright (C) 2016 MariaDB Corporation
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; version 2 of
7 the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 MA 02110-1301, USA. */
18
19 /*
20 * $Id: stats.cpp 699 2008-09-09 19:44:18Z rdempsey $
21 */
22
23 #include <ctime>
24 #include <sys/time.h>
25 #include <pthread.h>
26 #include <iomanip>
27 #include <map>
28 #define NDEBUG
29 #include <cassert>
30 #include <csignal>
31 using namespace std;
32
33 #include <boost/thread.hpp>
34 #include <boost/shared_ptr.hpp>
35 using namespace boost;
36
37 #include "stats.h"
38 #include "messagelog.h"
39
40 using namespace BRM;
41
42 namespace
43 {
44
pause_(unsigned delay)45 void pause_(unsigned delay)
46 {
47 struct timespec req;
48 struct timespec rem;
49
50 req.tv_sec = delay;
51 req.tv_nsec = 0;
52
53 rem.tv_sec = 0;
54 rem.tv_nsec = 0;
55
56 again:
57
58 if (nanosleep(&req, &rem) != 0)
59 if (rem.tv_sec > 0 || rem.tv_nsec > 0)
60 {
61 req = rem;
62 goto again;
63 }
64 }
65
timestr()66 const string timestr()
67 {
68 // Get a timestamp for output.
69 struct tm tm;
70 struct timeval tv;
71
72 gettimeofday(&tv, 0);
73 localtime_r(&tv.tv_sec, &tm);
74
75 ostringstream oss;
76 oss << setfill('0')
77 << setw(2) << tm.tm_hour << ':'
78 << setw(2) << tm.tm_min << ':'
79 << setw(2) << tm.tm_sec << '.'
80 << setw(4) << tv.tv_usec / 100;
81
82 return oss.str();
83 }
84
85 class TraceFile
86 {
87 public:
TraceFile(uint32_t sessionID,const char * name)88 TraceFile(uint32_t sessionID, const char* name)
89 {
90 if (sessionID > 0 )
91 {
92 const char* outName;
93
94 if (name == 0)
95 outName = "lbids";
96 else
97 outName = name;
98
99 ostringstream oss;
100 oss << MCSLOGDIR << "/trace/" << outName << '.' << sessionID;
101 oFile.reset(new ofstream());
102 oFile->open(oss.str().c_str(), ios_base::out | ios_base::ate | ios_base::app);
103 }
104 }
105
~TraceFile()106 ~TraceFile()
107 {
108 }
109
close()110 void close()
111 {
112 if (oFile)
113 {
114 oFile->close();
115 }
116 }
117
log(OID_t oid,uint64_t lbid,pthread_t thdid,char event='\\0')118 void log(OID_t oid, uint64_t lbid, pthread_t thdid, char event = '\0')
119 {
120 *oFile << oid << ' ' << timestr() << ' ' << lbid
121 << ' ' << thdid;
122
123 if (event != '\0')
124 *oFile << ' ' << event;
125
126 *oFile << endl;
127 oFile->flush();
128 }
129
130 private:
131 //Compiler defaults okay
132 //TraceFile(const TraceFile& rhs);
133 //TraceFile operator=(const TraceFile& rhs);
134 shared_ptr<ofstream> oFile;
135
136 };
137
138 struct TraceFileInfo
139 {
TraceFileInfo__anon76292fca0111::TraceFileInfo140 TraceFileInfo(uint32_t session = 0, const char* name = 0) : traceFile(session, name), lastTouched(0) { }
~TraceFileInfo__anon76292fca0111::TraceFileInfo141 ~TraceFileInfo() { }
142
log__anon76292fca0111::TraceFileInfo143 void log(OID_t oid, uint64_t lbid, pthread_t thdid, char event = '\0')
144 {
145 traceFile.log(oid, lbid, thdid, event);
146 lastTouched = time(0);
147 }
148
close__anon76292fca0111::TraceFileInfo149 void close()
150 {
151 traceFile.close();
152 }
153
154 TraceFile traceFile;
155 time_t lastTouched;
156
157 private:
158 //Compiler defaults okay
159 //TraceFileInfo(const TraceFileInfo& rhs);
160 //TraceFileInfo operator=(const TraceFileInfo& rhs);
161 };
162
163 //map a session id to a trace file
164 typedef map<uint32_t, TraceFileInfo> TraceFileMap_t;
165
166 TraceFileMap_t traceFileMap;
167 //map mutex
168 mutex traceFileMapMutex;
169
170 class StatMon
171 {
172 public:
StatMon()173 StatMon()
174 {
175 sigset_t sigset;
176 sigemptyset(&sigset);
177 sigaddset(&sigset, SIGPIPE);
178 sigaddset(&sigset, SIGUSR1);
179 sigaddset(&sigset, SIGUSR2);
180 pthread_sigmask(SIG_BLOCK, &sigset, 0);
181 }
operator ()() const182 void operator()() const
183 {
184 //struct timespec ts = { 60 * 1, 0 };
185 mutex::scoped_lock lk(traceFileMapMutex);
186 TraceFileMap_t::iterator iter;
187 TraceFileMap_t::iterator end;
188
189 for (;;)
190 {
191 lk.unlock();
192 time_t beforeSleep = time(0);
193 //nanosleep(&ts, 0);
194 pause_(60);
195 lk.lock();
196 iter = traceFileMap.begin();
197 end = traceFileMap.end();
198
199 while (iter != end)
200 {
201 if (iter->second.lastTouched < beforeSleep)
202 {
203 //remove this session trace file
204 iter->second.close();
205 traceFileMap.erase(iter++);
206 }
207 else
208 ++iter;
209 }
210 }
211 }
212 private:
213 //Compiler defaults okay
214 //StatMon(const StatMon& rhs);
215 //StatMon operator=(const StatMon& rhs);
216 };
217
218 }
219
220 namespace dbbc
221 {
222
Stats()223 Stats::Stats() :
224 fMonitorp(0)
225 {
226
227 fMonitorp = new thread(StatMon());
228 }
229
Stats(const char * name)230 Stats::Stats(const char* name) :
231 fMonitorp(0), fName(name)
232 {
233 fMonitorp = new thread(StatMon());
234 //fName << name;
235 }
236
~Stats()237 Stats::~Stats()
238 {
239 delete fMonitorp;
240 }
241
touchedLBID(uint64_t lbid,pthread_t thdid,uint32_t session)242 void Stats::touchedLBID(uint64_t lbid, pthread_t thdid, uint32_t session)
243 {
244 if (lbid < 0 || session == 0) return;
245
246 mutex::scoped_lock lk(traceFileMapMutex);
247 TraceFileMap_t::iterator iter = traceFileMap.find(session);
248
249 if (iter == traceFileMap.end())
250 {
251 traceFileMap[session] = TraceFileInfo(session);
252 iter = traceFileMap.find(session);
253 idbassert(iter != traceFileMap.end());
254 }
255
256 iter->second.log(lbid2oid(lbid), lbid, thdid);
257 }
258
markEvent(const uint64_t lbid,const pthread_t thdid,const uint32_t session,const char event)259 void Stats::markEvent(const uint64_t lbid, const pthread_t thdid, const uint32_t session, const char event)
260 {
261 if (lbid < 0 || session == 0) return;
262
263 mutex::scoped_lock lk(traceFileMapMutex);
264 TraceFileMap_t::iterator iter = traceFileMap.find(session);
265
266 if (iter == traceFileMap.end())
267 {
268 traceFileMap[session] = TraceFileInfo(session, fName);
269 iter = traceFileMap.find(session);
270 idbassert(iter != traceFileMap.end());
271 }
272
273 iter->second.log(lbid2oid(lbid), lbid, thdid, event);
274 }
275
276 }
277
278