1 /* Copyright (C) 2014 InfiniDB, Inc.
2 
3    This program is free software; you can redistribute it and/or
4    modify it under the terms of the GNU General Public License
5    as published by the Free Software Foundation; version 2 of
6    the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16    MA 02110-1301, USA. */
17 
18 /******************************************************************************
19  * $Id: sessionmonitor.h 9210 2013-01-21 14:10:42Z rdempsey $
20  *
21  *****************************************************************************/
22 
23 /** @file
24  * class SessionMonitor interface
25  */
26 
27 #ifndef _SESSIONMONITOR_H
28 #define _SESSIONMONITOR_H
29 
30 #include <vector>
31 #include <exception>
32 #include <sys/types.h>
33 #include <unistd.h>
34 
35 #include "calpontsystemcatalog.h"
36 #include "sessionmanager.h"
37 #include "shmkeys.h"
38 #include "brmtypes.h"
39 
40 //#define SM_DEBUG
41 
42 namespace execplan
43 {
44 
45 /** @brief Identifies stale and orphaned transaction IDs.
46  *
47  *
48  * This class uses 2 parameters from the Columnstore.xml file:
49  * SessionManager/MaxConcurrentTransactions: defines how many active transactions the
50  *		system should support.	When a new request comes in and there are already
51  *		MaxConcurrentTransactions active, the new request blocks by default.  The
52  *		default value is 1000.
53  *
54  * SessionMonitor/SharedMemoryTmpFile: the file to store the shared memory segment
55  *		data in.  This needs to be a different file than
56  *		file used for the SessionManager/SharedMemoryTmpFile.
57  */
58 
59 /*
60  * NOTE: It seems that valgrind doesn't work well with shared memory segments.
61  * Specifically, when the code executes shmctl(IPC_RMID), which normally means
62  * "destroy the segment when refcount == 0", the segment is destroyed
63  * immediately, causing all subsequent references to fail.	This only affects
64  * 'leakcheck'.
65  * This comment is originally from SessionManager.h. I am assuming we will see
66  * the same behavior here.
67  */
68 
69 class SessionMonitor
70 {
71 public:
72 
73     /** @brief A type describing a single transaction ID */
74     struct MonTxnID
75     {
76         /// The TransactionID number
77         CalpontSystemCatalog::SCN	id;
78         /// True if the id is valid.
79         bool						valid;
80         /// timestamp of firstrecord of this TID
81         time_t						firstrecord;
MonTxnIDMonTxnID82         MonTxnID()
83         {
84             id = 0;
85             valid = false;
86             firstrecord = 0;
87         };
88     };
89 
90     /** @brief A type describing a single transaction ID */
91     typedef struct MonTxnID MonTxnID;
92 
93     /** @brief A type associating a session with a transaction */
94     struct MonSIDTIDEntry
95     {
96         /// The Transaction ID.  txnid.valid determines whether or not this SIDTIDEntry is valid
97         MonTxnID			txnid;
98         /// The session doing the transaction
99         SessionManager::SID		sessionid;
MonSIDTIDEntryMonSIDTIDEntry100         MonSIDTIDEntry()
101         {
102             txnid = MonTxnID();
103             sessionid = 0;
104         };
105     };
106 
107     /** @brief A type associating a session with a transaction */
108     typedef struct MonSIDTIDEntry MonSIDTIDEntry_t;
109 
110     /** @brief Vector of MonSIDTIDEntry structures */
111     typedef std::vector<MonSIDTIDEntry_t*> MonSIDTIDEntryVector_t;
112 
113     /** @brief needed to sort txns list in find timedOutTnxs()*/
114     struct lessMonSIDTIDEntry
115     {
operatorlessMonSIDTIDEntry116         bool operator()(MonSIDTIDEntry const* p1, MonSIDTIDEntry const* p2)
117         {
118             if (!p1)
119                 return true;
120 
121             if (!p2)
122                 return false;
123 
124             return p1->txnid.firstrecord < p2->txnid.firstrecord;
125         }
126     };
127 
128     /** @brief monitor version of the SessionManagerData */
129     struct SessionMonitorData_struct
130     {
131         int txnCount;
132         CalpontSystemCatalog::SCN verID;
133         MonSIDTIDEntry_t* activeTxns;
SessionMonitorData_structSessionMonitorData_struct134         SessionMonitorData_struct()
135         {
136             txnCount = 0;
137             verID = 0;
138             activeTxns = NULL;
139         };
140     };
141     typedef struct SessionMonitorData_struct	SessionMonitorData_t;
142 
143     /** @brief typedef if SessionManager struct SIDTIDEntry. For convenience.*/
144     typedef BRM::SIDTIDEntry SIDTIDEntry_t;
145     /** @brief This struct describes the layout of the shared memory segment copied from SessionManager.h */
146     struct SessionManagerData_struct
147     {
148         int txnCount;
149         CalpontSystemCatalog::SCN verID;
150         CalpontSystemCatalog::SCN syscatVerID;
151         int systemstate;
152         boost::interprocess::interprocess_semaphore sems[2];
153         SIDTIDEntry_t activeTxns[];
154     };
155     typedef SessionManagerData_struct SessionManagerData_t;
156 
157     /** @brief Constructor
158      *
159      * This attaches to existing shared memory segments.
160      * @note throws ios_base::failure on file IO error, runtime_error for
161      * other types of errors.  It might be worthwhile to define additional
162      * exceptions for all the different types of failures that can happen
163      * here.
164      */
165     SessionMonitor();
166 
167     /** @brief Destructor
168      *
169      * This detaches the shared memory segment then saves it
170      * to disk and destroyed. It does not destroy the semaphores
171      * or the shared memory segment. Deletes the local copies
172      * of the SessionManager data and SessionMonitor data.
173      */
174     virtual ~SessionMonitor();
175 
maxTxns()176     const int maxTxns() const
177     {
178         return fMaxTxns;
179     }
180     const int txnCount() const;
181 
182     /**
183      * @brief identifies timed out SessionManager structures
184      * @param
185      * @return
186     */
187     MonSIDTIDEntryVector_t timedOutTxns();
188 
previousManagerData()189     const SessionMonitorData_t* previousManagerData()
190     {
191         return &fPrevSegment;
192     }
currentManagerData()193     SessionManagerData_t* currentManagerData()
194     {
195         return fCurrentSegment;
196     }
sessionManagerData()197     const SessionManagerData_t* sessionManagerData()
198     {
199         return fSessionManagerData;
200     }
201 
202     void printTxns(const MonSIDTIDEntry_t& txn) const;
203 #ifdef SM_DEBUG
204     void printSegment(const SessionManagerData_t* seg, const int l = 1000) const;
205     void printMonitorData(const int l = 1000) const;
206     void printTxns(const SIDTIDEntry_t& txn) const;
207 #endif
AgeLimit()208     const int AgeLimit() const
209     {
210         return fAgeLimit;   // to speed up testing
211     }
AgeLimit(const int & age)212     void AgeLimit(const int& age)
213     {
214         fAgeLimit = age;
215     }
segmentFilename()216     const char* segmentFilename() const
217     {
218         return fSegmentFilename.c_str();
219     }
haveSemaphores()220     bool haveSemaphores() const
221     {
222         return fHaveSemaphores;
223     }
haveSharedMemory()224     bool haveSharedMemory() const
225     {
226         return fIsAttached;
227     }
228 
229 private:
230 
231     int fMaxTxns;		// the maximum number of concurrent transactions
232     static const int fMaxRetries = 10; // the max number of retries on file IO
233     std::string fSegmentFilename; // filename used to store the image of the SessionManager data
234     time_t fDefaultAgeLimit;
235     time_t fAgeLimit; // age limit in seconds used to timeout/orpan a transaction
236 
237     SessionMonitorData_t fSessionMonitorData;	// pointer to in memory copy of the Monitor data
238     SessionMonitorData_t fPrevSegment;			// in memory copy of SessionManager data from backup file
239     SessionManagerData_t* fCurrentSegment;		// in memory of SessionManager data
240     SessionManagerData_t* fSessionManagerData;	// current shared memory SessionManager data
241 
242     // refers to 2 semaphores; the first is a mutex that guards the shmseg
243     // the second is used to block processes when there are too many concurrent txns
244     int fsems;
245     int fshmid; 	// shared memory segment id
246     uint32_t fuid; // user id used to create the shared memory key
247 
248     SessionManager sm;
249 
250     bool isStaleSIDTID(const SIDTIDEntry_t& src, const MonSIDTIDEntry_t& dest) const;
251     bool isEqualSIDTID(const SIDTIDEntry_t& src, const MonSIDTIDEntry_t& dest) const;
252     bool isUsedSIDTID(const SIDTIDEntry_t& e) const;
253     bool isUsed(const MonSIDTIDEntry_t& e) const;
254 
255     /**
256      * @brief attached to SessionManagerData shared memory
257      * @param
258      * @return void
259      */
260     void getSharedData(void);
261 
262     bool fIsAttached;
263 
264     /**
265      * @brief unattached from SessionManagerData shared memory
266      * @param
267      * @return void
268      */
269     void detachSegment(void);
270 
271     /**
272      * @brief initialize SessionMonitorData
273      * @param
274      * @return void
275      */
276     void initSegment(SessionMonitorData_t* seg);
277 
278     /**
279      * @brief initialize SessionManagerData
280      * @param
281      * @return void
282      */
283     void initSegment(SessionManagerData_t* seg);
284 
IPCKey()285     const key_t IPCKey() const
286     {
287         return fShmKeys.SESSIONMANAGER_SYSVKEY;
288     };
289 
290     /**
291      * @brief copies the SessionMonitor data from a file into memory
292      * @param
293      * @return void
294      */
295     void copyPreviousSegment();
296 
297     /**
298      * @brief copies the SessionManager data from shared memory into an SessionMonitor memory
299      * @param
300      * @return void
301      */
302     void copyCurrentSegment();
303 
304     /**
305      * @brief Reads the SM data from file into memory. Used by copyPreviousSegment().
306      * @param
307      * @return bool
308     */
309     bool readMonitorDataFromFile(const std::string);
310 
311     /**
312      * @brief write the current SessionManagerData as SessionMonitorData to a file.
313      * @param
314      * @return void
315      */
316     void saveAsMonitorData(const std::string);
317 
318     bool fHaveSemaphores;
319 
320     /**
321      * @brief get the SessionManager semaphores
322      * @param
323      * @return void
324      */
325     int getSems(void);
326 
327     void lock(void);
328 
329     void unlock(void);
330 
331     /**
332      * @brief do not use the copy constructor.
333      * @param
334      * @return
335      */
336     SessionMonitor(const SessionMonitor&);
337 
338 private:
339     BRM::ShmKeys fShmKeys;
340 };
341 
342 }	//namespace
343 
344 #endif
345