1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-06-06 08:21:01 +03:00
2016-06-01 20:03:20 -05:00

384 lines
9.4 KiB
C++

/* Copyright (C) 2014 InfiniDB, Inc.
Copyright (C) 2016 MariaDB Corporaton
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: bppseeder.cpp 2035 2013-01-21 14:12:19Z rdempsey $
// C++ Implementation: bppseeder
//
// Description:
//
//
// Author: Patrick <pleblanc@localhost.localdomain>, (C) 2008
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include <unistd.h>
#include <sstream>
#ifndef _MSC_VER
#include <pthread.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#else
typedef int pthread_t;
#endif
#include <boost/thread.hpp>
#include "bppseeder.h"
#include "primitiveserver.h"
#include "pp_logger.h"
#include "errorcodes.h"
#include "calpontsystemcatalog.h"
#include "blockcacheclient.h"
using namespace messageqcpp;
using namespace std;
namespace primitiveprocessor
{
struct PTLogs{
PTLogs() {};
PTLogs(const int t, const char * fname):thdId(t) {logFD.open(fname, ios_base::app | ios_base::ate);}
~PTLogs() {logFD.close();}
int thdId;
ofstream logFD;
};
typedef PTLogs PTLogs_t;
typedef boost::shared_ptr<PTLogs_t> SPPTLogs_t;
typedef std::tr1::unordered_map<pthread_t, SPPTLogs_t> PTLogsMap_t;
PTLogsMap_t gFDList;
SPPTLogs_t gLogFD;
boost::mutex gFDMutex; //pthread_mutex_t gFDMutex=PTHREAD_MUTEX_INITIALIZER;
int gThdCnt=0;
extern dbbc::BlockRequestProcessor **BRPp;
extern int fCacheCount;
void timespec_sub(const struct timespec &tv1,
const struct timespec &tv2,
double &tm)
{
tm = (double)(tv2.tv_sec - tv1.tv_sec) + 1.e-9*(tv2.tv_nsec - tv1.tv_nsec);
}
BPPSeeder::BPPSeeder(const SBS &b,
const SP_UM_MUTEX& w,
const SP_UM_IOSOCK& s,
const int pmThreads,
const bool trace) :
bs(b), writelock(w), sock(s), fPMThreads(pmThreads), fTrace(trace),
failCount(0),
firstRun(true)
{
uint8_t *buf = b->buf();
uint32_t pos = sizeof(ISMPacketHeader);
sessionID = *((uint32_t *) &buf[pos]); pos += 4;
stepID = *((uint32_t *) &buf[pos]); pos += 4;
uniqueID = *((uint32_t *) &buf[pos]); pos +=4;
_priority = *((uint32_t *) &buf[pos]);
dieTime = boost::posix_time::second_clock::universal_time() +
boost::posix_time::seconds(100);
}
BPPSeeder::BPPSeeder(const BPPSeeder &b)
: bs(b.bs), writelock(b.writelock), sock(b.sock),
fPMThreads(b.fPMThreads), fTrace(b.fTrace), uniqueID(b.uniqueID),
sessionID(b.sessionID), stepID(b.stepID), failCount(b.failCount), bpp(b.bpp),
firstRun(b.firstRun), _priority(b._priority)
{
}
BPPSeeder::~BPPSeeder()
{
}
int BPPSeeder::operator()()
{
uint32_t pos;
const uint8_t *buf = bs->buf();
BPPMap::iterator it;
ostringstream logData;
struct timespec tm;
struct timespec tm2;
double tm3=0;
bool ptLock=false;
bool gotBPP = false;
PTLogs_t* logFD=NULL;
int ret = 0;
pthread_t tid=0;
boost::mutex::scoped_lock scoped(bppLock, boost::defer_lock_t());
try {
if (firstRun) {
pos = sizeof(ISMPacketHeader) - 2;
uint16_t status = *((uint16_t *) &buf[pos]); pos += 2;
sessionID = *((uint32_t *) &buf[pos]); pos += 4;
stepID = *((uint32_t *) &buf[pos]); pos += 4;
uniqueID = *((uint32_t *) &buf[pos]); pos += 4;
_priority = *((uint32_t *) &buf[pos]);
if (0 < status)
{
sendErrorMsg(uniqueID, status, stepID);
return ret;
}
//if (!(sessionID & 0x80000000))
//cout << "got request for <" << sessionID <<", " << stepID << ">\n";
scoped.lock();
if (!bppv) {
it = bppMap.find(uniqueID);
if (it == bppMap.end()) {
/* mitigate a small race between creation and use */
scoped.unlock();
if (boost::posix_time::second_clock::universal_time() > dieTime) {
#if 0 // for debugging
#ifndef _MSC_VER
boost::posix_time::ptime pt = boost::posix_time::microsec_clock::local_time();
if (sessionID & 0x80000000)
cout << "BPPSeeder couldn't find the sessionID/stepID pair. sessionID="
<< (int) (sessionID ^ 0x80000000) << " stepID=" << stepID << " (syscat)" << pt << endl;
else
cout << "BPPSeeder couldn't find the sessionID/stepID pair. sessionID="
<< sessionID << " stepID=" << stepID << pt << endl;
#endif
throw logic_error("BPPSeeder couldn't find the sessionID/stepID pair");
#endif
return 0;
}
// if (!isSysCat())
return -1;
// else { // syscat queries aren't run by a threadpool, can't reschedule those jobs
// usleep(1000);
// goto retry;
// }
}
bppv = it->second;
}
if (bppv->aborted())
return 0;
bpp = bppv->next();
scoped.unlock();
if (!bpp) {
// if (isSysCat()) {
// usleep(1000);
// goto retry;
// }
return -1; // all BPP instances are busy, make threadpool reschedule
}
gotBPP = true;
bpp->resetBPP(*bs, writelock, sock);
firstRun = false;
} // firstRun
if (fTrace)
{
PTLogsMap_t::iterator it;
#ifdef _MSC_VER
tid = GetCurrentThreadId();
#else
tid = pthread_self();
#endif
// only lock map while inserted objects
// once there is an object for each thread
// there is not need to lock
if (gFDList.size()<(uint32_t)fPMThreads) {
gFDMutex.lock();
ptLock=true;
}
it = gFDList.find(tid);
if (it==gFDList.end())
{
ostringstream LogFileName;
SPPTLogs_t spof;
#ifdef _MSC_VER
LogFileName << "C:/Calpont/log/trace/pt." << tid;
#else
LogFileName << "/var/log/mariadb/columnstore/trace/pt." << tid;
#endif
spof.reset(new PTLogs_t(gThdCnt, LogFileName.str().c_str()));
gThdCnt++;
// TODO: add error checking
if (spof->logFD.is_open()) {
gFDList[tid] = spof;
logFD = spof.get();
}
} else
logFD =(*it).second.get();
if (ptLock) {
gFDMutex.unlock();
ptLock=false;
}
clock_gettime(CLOCK_MONOTONIC, &tm);
} // if (fTrace)
uint32_t retries = 0;
restart:
try {
ret = (*bpp)();
}
catch (NeedToRestartJob &e) {
ostringstream os;
// experimentally the race can exist longer than 10s. "No way" should
// it take 10 minutes. If it does, the user will have to resubmit their
// query.
// 9/27/12 - changed the timeout to 2 mins b/c people report the system
// is hung if it does nothing for 10 mins. 2 mins should still be more
// than enough
if (++retries == 120) {
os << e.what() << ": Restarted a syscat job " << retries << " times, bailing\n";
throw NeedToRestartJob(os.str());
}
flushSyscatOIDs();
bs->rewind();
bpp->resetBPP(*bs, writelock, sock);
sleep(1);
goto restart;
}
if (ret)
return ret;
if (fTrace)
if (logFD && logFD->logFD.is_open()) {
clock_gettime(CLOCK_MONOTONIC, &tm2);
timespec_sub(tm, tm2, tm3);
logFD->logFD
<< left << setw(3) << logFD->thdId
<< right << fixed << ((double)(tm.tv_sec+(1.e-9*tm.tv_nsec))) << " "
<< right << fixed << tm3 << " "
<< right << setw(6) << bpp->getSessionID() << " "
<< right << setw(4) << bpp->getStepID() << " "
<< right << setw(2) << bpp->FilterCount() << " "
<< right << setw(2) << bpp->ProjectCount() << " "
<< right << setw(9) << bpp->PhysIOCount() << " "
<< right << setw(9) << bpp->CachedIOCount() << " "
<< right << setw(9) << bpp->BlocksTouchedCount()
<< endl;
} // if (logFD...
}
catch (scalar_exception &se)
{
if (gotBPP)
bpp->busy(false);
if (ptLock) {
gFDMutex.unlock();
ptLock=false;
}
}
catch(exception& ex)
{
if (gotBPP)
bpp->busy(false);
if (ptLock) {
gFDMutex.unlock();
ptLock=false;
}
catchHandler(ex.what(), uniqueID, stepID);
cout << "BPPSeeder step " << stepID << " caught an exception: " << ex.what() << endl;
}
catch(...)
{
if (gotBPP)
bpp->busy(false);
if (ptLock) {
gFDMutex.unlock();
ptLock=false;
}
string msg("BPPSeeder caught an unknown exception");
catchHandler(msg, uniqueID, stepID);
cout << msg << endl;
}
return ret;
}
void BPPSeeder::catchHandler(const string& ex, uint32_t id, uint32_t step)
{
Logger log;
log.logMessage(ex);
sendErrorMsg(id, logging::bppSeederErr, step);
}
void BPPSeeder::sendErrorMsg(uint32_t id, uint16_t status, uint32_t step)
{
ISMPacketHeader ism;
PrimitiveHeader ph = {0};
ism.Status = status;
ph.UniqueID = id;
ph.StepID = step;
ByteStream msg(sizeof(ISMPacketHeader) + sizeof(PrimitiveHeader));
msg.append((uint8_t *) &ism, sizeof(ism));
msg.append((uint8_t *) &ph, sizeof(ph));
boost::mutex::scoped_lock lk(*writelock);
sock->write(msg);
}
bool BPPSeeder::isSysCat()
{
const uint8_t *buf;
uint32_t sessionIDOffset = sizeof(ISMPacketHeader);
uint32_t sessionID;
buf = bs->buf();
sessionID = *((uint32_t *) &buf[sessionIDOffset]);
return (sessionID & 0x80000000);
}
uint32_t BPPSeeder::getID()
{
return uniqueID;
}
/* This is part of the syscat-retry hack. We should get rid of it once we
* track down the source of the problem.
*/
void BPPSeeder::flushSyscatOIDs()
{
vector<BRM::OID_t> syscatOIDs;
syscatOIDs = execplan::getAllSysCatOIDs();
for (int i = 0; i < fCacheCount; i++) {
dbbc::blockCacheClient bc(*BRPp[i]);
bc.flushOIDs((const uint32_t *) &syscatOIDs[0], syscatOIDs.size());
}
}
};