You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-31 18:30:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			515 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			515 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2014 InfiniDB, Inc.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU General Public License
 | |
|    as published by the Free Software Foundation; version 2 of
 | |
|    the License.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 | |
|    MA 02110-1301, USA. */
 | |
| 
 | |
| /*****************************************************************************
 | |
|  * $Id: sessionmonitor.cpp 9210 2013-01-21 14:10:42Z rdempsey $
 | |
|  *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| using namespace std;
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/ipc.h>
 | |
| #include <sys/sem.h>
 | |
| #include <sys/shm.h>
 | |
| #include <sys/types.h>
 | |
| #include <time.h>
 | |
| #include <fcntl.h>
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <iostream>
 | |
| #include <fstream>
 | |
| #include <string>
 | |
| #include <stdexcept>
 | |
| #include <ios>
 | |
| #include <vector>
 | |
| 
 | |
| #include "calpontsystemcatalog.h"
 | |
| #include "sessionmonitor.h"
 | |
| #include "configcpp.h"
 | |
| 
 | |
| #include "vendordmlstatement.h"
 | |
| #include "calpontdmlpackage.h"
 | |
| #include "calpontdmlfactory.h"
 | |
| using namespace dmlpackage;
 | |
| 
 | |
| #include "bytestream.h"
 | |
| #include "messagequeue.h"
 | |
| using namespace messageqcpp;
 | |
| 
 | |
| using namespace BRM;
 | |
| 
 | |
| #include "installdir.h"
 | |
| 
 | |
| namespace execplan
 | |
| {
 | |
| SessionMonitor::SessionMonitor()
 | |
| {
 | |
|   config::Config* conf;
 | |
|   int madeSems;
 | |
|   string stmp;
 | |
| 
 | |
|   fuid = getuid();
 | |
|   conf = config::Config::makeConfig();
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     stmp = conf->getConfig("SessionManager", "MaxConcurrentTransactions");
 | |
|   }
 | |
|   catch (exception& e)
 | |
|   {
 | |
|     cout << e.what() << endl;
 | |
|     stmp.empty();
 | |
|   }
 | |
| 
 | |
|   int tmp = static_cast<int>(config::Config::fromText(stmp));
 | |
| 
 | |
|   if (tmp <= 0)
 | |
|     fMaxTxns = 1000;
 | |
|   else
 | |
|     fMaxTxns = tmp;
 | |
| 
 | |
|   stmp.clear();
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     stmp = conf->getConfig("SessionMonitor", "SharedMemoryTmpFile");
 | |
|   }
 | |
|   catch (exception& e)
 | |
|   {
 | |
|     cout << e.what() << endl;
 | |
|     stmp.empty();
 | |
|   }
 | |
| 
 | |
|   // Instantiate/delete a SessionManager to make sure it's shared memory segments are present.
 | |
|   SessionManager* mgr = new SessionManager();
 | |
|   delete mgr;
 | |
| 
 | |
|   if (stmp != "")
 | |
|     fSegmentFilename = strdup(stmp.c_str());
 | |
|   else
 | |
|   {
 | |
|     string tmpdir = "/var/lib/columnstore/CalpontSessionMonitorShm";
 | |
| 
 | |
|     fSegmentFilename = strdup(tmpdir);
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     madeSems = getSems();
 | |
|     fHaveSemaphores = true;
 | |
|   }
 | |
|   catch (...)
 | |
|   {
 | |
|     fHaveSemaphores = false;
 | |
|   }
 | |
| 
 | |
|   stmp.clear();
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     stmp = conf->getConfig("SessionMonitor", "TransactionAgeLimit");
 | |
|   }
 | |
|   catch (exception& e)
 | |
|   {
 | |
|     cerr << e.what() << endl;
 | |
|     stmp.empty();
 | |
|   }
 | |
| 
 | |
|   tmp = static_cast<int>(config::Config::fromText(stmp));
 | |
| 
 | |
|   if (tmp <= 0)
 | |
|     fAgeLimit = fDefaultAgeLimit;
 | |
|   else
 | |
|     fAgeLimit = tmp;
 | |
| 
 | |
|   fIsAttached = false;
 | |
|   getSharedData();
 | |
|   unlock();
 | |
|   fCurrentSegment = NULL;
 | |
|   fPrevSegment.activeTxns = NULL;
 | |
| 
 | |
|   if (haveSharedMemory())
 | |
|     copyCurrentSegment();
 | |
| 
 | |
|   if (haveSemaphores())
 | |
|     copyPreviousSegment();
 | |
| }
 | |
| 
 | |
| SessionMonitor::SessionMonitor(const SessionMonitor& sm)
 | |
| {
 | |
| }
 | |
| 
 | |
| SessionMonitor::~SessionMonitor()
 | |
| {
 | |
|   saveAsMonitorData(segmentFilename());
 | |
| 
 | |
|   if (fSessionManagerData != NULL)
 | |
|   {
 | |
|     lock();
 | |
|     detachSegment();
 | |
|     unlock();
 | |
|   }
 | |
| 
 | |
|   // delete [] fCurrentSegment;
 | |
|   // delete [] fSessionMonitorData.activeTxns;
 | |
|   // delete [] fPrevSegment.activeTxns;
 | |
| }
 | |
| 
 | |
| void SessionMonitor::detachSegment()
 | |
| {
 | |
|   // delete [] fSessionManagerData;
 | |
| 
 | |
|   fIsAttached = false;
 | |
| }
 | |
| 
 | |
| // returns 1 if it attached to pre-existing semaphores, else it throws exception.
 | |
| int SessionMonitor::getSems()
 | |
| {
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| void SessionMonitor::lock()
 | |
| {
 | |
| }
 | |
| 
 | |
| void SessionMonitor::unlock()
 | |
| {
 | |
| }
 | |
| 
 | |
| void SessionMonitor::printTxns(const MonSIDTIDEntry& txn) const
 | |
| {
 | |
|   cout << "sessionid " << txn.sessionid << " txnid " << txn.txnid.id << " valid "
 | |
|        << (txn.txnid.valid == true ? "TRUE" : "FALSE") << " time_t " << txn.txnid.firstrecord << " tdiff "
 | |
|        << time(NULL) - txn.txnid.firstrecord << " ctime " << ctime(&txn.txnid.firstrecord);
 | |
| }
 | |
| 
 | |
| #ifdef SM_DEBUG
 | |
| void SessionMonitor::printTxns(const SessionManager::SIDTIDEntry& txn) const
 | |
| {
 | |
|   cout << "sessionid " << txn.sessionid << " txnid " << txn.txnid.id << " valid "
 | |
|        << (txn.txnid.valid == true ? "TRUE" : "FALSE") << endl;
 | |
| }
 | |
| 
 | |
| void SessionMonitor::printMonitorData(const int len) const
 | |
| {
 | |
|   MonSIDTIDEntry* txns = fPrevSegment.activeTxns;
 | |
| 
 | |
|   cout << "Monitor txnCount " << fPrevSegment.txnCount << " verID " << fPrevSegment.verID << endl;
 | |
| 
 | |
|   for (int idx = 0; txns && idx < len; idx++)
 | |
|   {
 | |
|     printTxns(txns[idx]);
 | |
|   }
 | |
| 
 | |
|   cout << "==" << endl;
 | |
| }
 | |
| 
 | |
| void SessionMonitor::printSegment(const SessionManagerData_t* seg, const int len) const
 | |
| {
 | |
|   if (seg == NULL)
 | |
|   {
 | |
|     cerr << "No SessionManagerData" << endl;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   cout << "Manager txnCount " << seg->txnCount << " verID " << seg->verID << endl;
 | |
| 
 | |
|   for (int idx = 0; idx < len; idx++)
 | |
|   {
 | |
|     printTxns(seg->activeTxns[idx]);
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void SessionMonitor::getSharedData()
 | |
| {
 | |
|   int len;
 | |
| 
 | |
|   fSessionManagerData = reinterpret_cast<SessionManagerData_t*>(sm.getShmContents(len));
 | |
| 
 | |
|   if (fSessionManagerData == NULL)
 | |
|   {
 | |
|     cerr << "SessionMonitor::getSharedData(): getShmContents() failed" << endl;
 | |
|     throw runtime_error("SessionMonitor::getSharedData(): getShmContents() failed.  Check the error log.");
 | |
|   }
 | |
| 
 | |
|   fIsAttached = true;
 | |
| }
 | |
| 
 | |
| void SessionMonitor::initSegment(SessionMonitorData_t* seg)
 | |
| {
 | |
|   if (!seg)
 | |
|     return;
 | |
| 
 | |
|   seg->txnCount = 0;
 | |
|   seg->verID = 0;
 | |
|   int size = maxTxns() * sizeof(MonSIDTIDEntry_t);
 | |
| 
 | |
|   if (seg->activeTxns)
 | |
|     memset(seg->activeTxns, 0, size);
 | |
| }
 | |
| 
 | |
| void SessionMonitor::initSegment(SessionManagerData_t* seg)
 | |
| {
 | |
|   if (!seg)
 | |
|     return;
 | |
| 
 | |
|   int size = maxTxns() * sizeof(SIDTIDEntry_t);
 | |
|   seg->txnCount = 0;
 | |
|   seg->verID = 0;
 | |
|   memset(seg->activeTxns, 0, size);
 | |
| }
 | |
| 
 | |
| void SessionMonitor::copyPreviousSegment()
 | |
| {
 | |
|   try
 | |
|   {
 | |
|     bool loadSuccessful = readMonitorDataFromFile(segmentFilename());
 | |
| 
 | |
|     if (!loadSuccessful)
 | |
|     {
 | |
|       saveAsMonitorData(segmentFilename());
 | |
|       readMonitorDataFromFile(segmentFilename());
 | |
|     }
 | |
|   }
 | |
|   catch (...)
 | |
|   {
 | |
|     saveAsMonitorData(segmentFilename());
 | |
|     readMonitorDataFromFile(segmentFilename());
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool SessionMonitor::readMonitorDataFromFile(const std::string filename)
 | |
| {
 | |
|   int err = 0;
 | |
|   uint32_t headerSize = 2 * sizeof(int);
 | |
|   char* data = reinterpret_cast<char*>(&fPrevSegment);
 | |
|   int fd = open(filename.c_str(), O_RDONLY);
 | |
| 
 | |
|   if (fd < 0)
 | |
|   {
 | |
|     perror("SessionMonitor::readMonitorDataFromFile(): open");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   err = read(fd, data, headerSize);
 | |
| 
 | |
|   if (err < 0)
 | |
|   {
 | |
|     if (errno != EINTR)
 | |
|     {
 | |
|       perror("SessionMonitor::readMonitorDataFromFile(): read");
 | |
|     }
 | |
|   }
 | |
|   else if (err == 0)
 | |
|   {
 | |
|     close(fd);
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   int dataSize = maxTxns() * sizeof(MonSIDTIDEntry_t);
 | |
|   delete[] fPrevSegment.activeTxns;
 | |
| 
 | |
|   fPrevSegment.activeTxns = new MonSIDTIDEntry[maxTxns()];
 | |
|   data = reinterpret_cast<char*>(fPrevSegment.activeTxns);
 | |
|   memset(data, 0, sizeof(MonSIDTIDEntry) * maxTxns());
 | |
|   err = read(fd, data, dataSize);
 | |
| 
 | |
|   if (err < 0)
 | |
|   {
 | |
|     if (errno != EINTR)
 | |
|     {
 | |
|       perror("SessionMonitor::readMonitorDataFromFile(): read");
 | |
|     }
 | |
|   }
 | |
|   else if (err == 0)
 | |
|   {
 | |
|     close(fd);
 | |
|     perror("SessionMonitor::readMonitorDataFromFile(): read 0");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   close(fd);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void SessionMonitor::saveAsMonitorData(const std::string)
 | |
| {
 | |
|   int fd;
 | |
|   int err = 0;
 | |
|   char* data = reinterpret_cast<char*>(&fSessionMonitorData);
 | |
| 
 | |
|   if (!fSessionMonitorData.activeTxns)
 | |
|   {
 | |
|     fSessionMonitorData.activeTxns = new MonSIDTIDEntry[maxTxns()];
 | |
|   }
 | |
| 
 | |
|   initSegment(&fSessionMonitorData);
 | |
| 
 | |
|   // get the most recent SessionManagerData
 | |
|   copyCurrentSegment();
 | |
|   fSessionMonitorData.txnCount = fCurrentSegment->txnCount;
 | |
|   fSessionMonitorData.verID = fCurrentSegment->verID;
 | |
| 
 | |
|   for (int idx = 0; idx < maxTxns(); idx++)
 | |
|   {
 | |
|     // is this a new txns or previously existing
 | |
|     MonSIDTIDEntry* monitor = &fSessionMonitorData.activeTxns[idx];
 | |
|     MonSIDTIDEntry* prevMonitor = (fPrevSegment.activeTxns ? &fPrevSegment.activeTxns[idx] : NULL);
 | |
|     SIDTIDEntry* manager = &fCurrentSegment->activeTxns[idx];
 | |
| 
 | |
|     if (prevMonitor)
 | |
|     {
 | |
|       if (!isEqualSIDTID(*manager, *prevMonitor))
 | |
|       {
 | |
|         monitor->txnid.firstrecord = time(NULL);
 | |
|       }
 | |
|       else if (isEqualSIDTID(*manager, *prevMonitor) && isUsed(*prevMonitor))
 | |
|       {
 | |
|         if (prevMonitor && prevMonitor->txnid.firstrecord == 0)
 | |
|           monitor->txnid.firstrecord = time(NULL);
 | |
|         else
 | |
|           monitor->txnid.firstrecord = prevMonitor->txnid.firstrecord;
 | |
|       }
 | |
|       else if (manager->txnid.valid == false && monitor->txnid.id == manager->txnid.id)
 | |
|         monitor->txnid.firstrecord = 0;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if (manager->txnid.valid && manager->txnid.id)
 | |
|       {
 | |
|         monitor->txnid.firstrecord = time(NULL);
 | |
|       }
 | |
|       else
 | |
|         monitor->txnid.firstrecord = 0;
 | |
|     }
 | |
| 
 | |
|     monitor->sessionid = manager->sessionid;
 | |
|     monitor->txnid.id = manager->txnid.id;
 | |
|     monitor->txnid.valid = manager->txnid.valid;
 | |
|   }
 | |
| 
 | |
|   // Always write to a new empty file
 | |
|   fd = open(segmentFilename(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
 | |
| 
 | |
|   if (fd < 0)
 | |
|   {
 | |
|     perror("SessionMonitor::saveAsMonitorData(): open");
 | |
|     throw ios_base::failure("SessionMonitor::saveAsMonitorData(): open failed.	Check the error log.");
 | |
|   }
 | |
| 
 | |
|   int headerSize = 2 * (sizeof(int));
 | |
|   err = write(fd, data, headerSize);
 | |
| 
 | |
|   if (err < 0)
 | |
|   {
 | |
|     if (errno != EINTR)
 | |
|       perror("SessionMonitor::saveAsMonitorData(): write");
 | |
|   }
 | |
| 
 | |
|   int dataSize = maxTxns() * sizeof(MonSIDTIDEntry);
 | |
|   data = reinterpret_cast<char*>(fSessionMonitorData.activeTxns);
 | |
|   err = write(fd, data, dataSize);
 | |
| 
 | |
|   if (err < 0)
 | |
|   {
 | |
|     if (errno != EINTR)
 | |
|       perror("SessionMonitor::saveAsMonitorData(): write");
 | |
|   }
 | |
| 
 | |
|   close(fd);
 | |
| }
 | |
| 
 | |
| void SessionMonitor::copyCurrentSegment()
 | |
| {
 | |
|   const int cpsize = 4 * sizeof(int) + 2 * sizeof(boost::interprocess::interprocess_semaphore) +
 | |
|                      maxTxns() * sizeof(SIDTIDEntry);
 | |
| 
 | |
|   delete[] reinterpret_cast<char*>(fCurrentSegment);
 | |
| 
 | |
|   fCurrentSegment = reinterpret_cast<SessionManagerData_t*>(new char[cpsize]);
 | |
|   lock();
 | |
|   memcpy(fCurrentSegment, fSessionManagerData, cpsize);
 | |
|   unlock();
 | |
| }
 | |
| 
 | |
| bool SessionMonitor::isUsed(const MonSIDTIDEntry& e) const
 | |
| {
 | |
|   if (e.sessionid == 0 && e.txnid.id == 0 && e.txnid.valid == false && e.txnid.firstrecord == 0)
 | |
|     return false;
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool SessionMonitor::isUsedSIDTID(const SIDTIDEntry& e) const
 | |
| {
 | |
|   if (e.sessionid == 0 && e.txnid.id == 0 && e.txnid.valid == false)
 | |
|     return false;
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool SessionMonitor::isStaleSIDTID(const SIDTIDEntry& a, const MonSIDTIDEntry& b) const
 | |
| {
 | |
|   if (b.txnid.valid && isEqualSIDTID(a, b) && b.txnid.firstrecord &&
 | |
|       (time(NULL) - b.txnid.firstrecord) > fAgeLimit)
 | |
|     return true;
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool SessionMonitor::isEqualSIDTID(const SIDTIDEntry& a, const MonSIDTIDEntry& b) const
 | |
| {
 | |
|   if (a.sessionid == b.sessionid && a.txnid.id == b.txnid.id && a.txnid.valid == b.txnid.valid)
 | |
|     return true;
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| vector<SessionMonitor::MonSIDTIDEntry_t*> SessionMonitor::timedOutTxns()
 | |
| {
 | |
|   vector<MonSIDTIDEntry_t*> txnsVec;
 | |
| 
 | |
|   copyCurrentSegment();
 | |
| 
 | |
|   if (fCurrentSegment && fPrevSegment.activeTxns != NULL)
 | |
|   {
 | |
|     for (int idx = 0; fCurrentSegment->activeTxns && fPrevSegment.activeTxns && idx < maxTxns(); idx++)
 | |
|     {
 | |
|       if (isUsedSIDTID(fCurrentSegment->activeTxns[idx]) &&
 | |
|           isStaleSIDTID(fCurrentSegment->activeTxns[idx], fPrevSegment.activeTxns[idx]))
 | |
|       {
 | |
|         txnsVec.push_back(&fPrevSegment.activeTxns[idx]);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     sort(txnsVec.begin(), txnsVec.end(), lessMonSIDTIDEntry());
 | |
|   }
 | |
| 
 | |
|   return txnsVec;
 | |
| }
 | |
| 
 | |
| const int SessionMonitor::txnCount() const
 | |
| {
 | |
|   return fSessionMonitorData.txnCount;
 | |
| }
 | |
| 
 | |
| }  // namespace execplan
 |