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