/* 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: we_workers.cpp 4450 2013-01-21 14:13:24Z rdempsey $ * ****************************************************************************/ #include "we_bulkload.h" #include "we_bulkstatus.h" #include "we_stats.h" #include #include #include "dataconvert.h" #include using namespace std; using namespace dataconvert; namespace WriteEngine { //------------------------------------------------------------------------------ // Puts the current thread to sleep for the specified number of milliseconds. //------------------------------------------------------------------------------ void BulkLoad::sleepMS(long ms) { struct timespec rm_ts; rm_ts.tv_sec = ms/1000; rm_ts.tv_nsec = ms%1000 *1000000; #ifdef _MSC_VER Sleep(ms); #else struct timespec abs_ts; do { abs_ts.tv_sec = rm_ts.tv_sec; abs_ts.tv_nsec = rm_ts.tv_nsec; } while(nanosleep(&abs_ts,&rm_ts) < 0); #endif } //------------------------------------------------------------------------------ // This is the main entry point method for each Read thread. // id is the one-up number (starting at 0) associated with each Read thread. //------------------------------------------------------------------------------ void BulkLoad::read(int id) { #ifdef PROFILE Stats::registerReadProfThread( ); #endif // First get a table to work on. // Acquire the read mutex // Iterate over the table list // if the table's status is new, set the locker = id // and then exit. int tableId = -1; try { // // LOOP to select and read the next table // while(true) { tableId = -1; #ifdef PROFILE Stats::startReadEvent(WE_STATS_WAIT_TO_SELECT_TBL); #endif if((tableId = lockTableForRead(id)) == -1) { fLog.logMsg( "BulkLoad::ReadOperation No more tables " "available for processing. Read thread " + Convertor::int2Str(id) + " exiting...", MSGLVL_INFO2); #ifdef PROFILE Stats::stopReadEvent(WE_STATS_WAIT_TO_SELECT_TBL); #endif return; } #ifdef PROFILE Stats::stopReadEvent(WE_STATS_WAIT_TO_SELECT_TBL); #endif int rc = fTableInfo[tableId].readTableData( ); if (rc != NO_ERROR) { // Error occurred while reading the data, break out of loop. BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; oss << "Bulkload Read (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << ". Terminating this job."; fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); fLog.logMsg( oss.str(), rc, MSGLVL_CRITICAL ); break; } } } catch (SecondaryShutdownException& ex) { // We are bailing out because another thread set bad job status ostringstream oss; if (tableId != -1) oss << "Bulkload Read (thread " << id << ") Stopped reading Table " << fTableInfo[tableId].getTableName() << ". " << ex.what(); else oss << "Bulkload Read (thread " << id << ") Stopped reading Tables. " << ex.what(); fLog.logMsg( oss.str(), MSGLVL_INFO1 ); } catch (exception& ex) { BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; if (tableId != -1) oss << "Bulkload Read (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << ". " << ex.what() << ". Terminating this job."; else oss << "Bulkload Read (thread " << id << ") Failed for Table. " << ex.what() << ". Terminating this job."; if(tableId != -1) fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); fLog.logMsg( oss.str(), ERR_UNKNOWN, MSGLVL_CRITICAL ); } catch (...) { BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; if (tableId != -1) oss << "Bulkload Read (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << ". Terminating this job."; else oss << "Bulkload Read (thread " << id << ") Failed for Table. Terminating this job."; if(tableId != -1) fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); fLog.logMsg( oss.str(), ERR_UNKNOWN, MSGLVL_CRITICAL ); } } //------------------------------------------------------------------------------ // Search for an available table to be read. // First available table that is found, is locked and assigned to the specified // thread id. // Return value is -1 if no table is available for reading. //------------------------------------------------------------------------------ int BulkLoad::lockTableForRead(int id) { boost::mutex::scoped_lock lock(fReadMutex); for(unsigned i=0; i= 100) { time_t t = time(0); char timeString[50]; ctime_r(&t, timeString); timeString[ strlen(timeString)-1 ] = '\0'; ostringstream oss; oss << endl << endl << timeString << ": BulkLoad::parse(" << id << "); " << #ifdef _MSC_VER " Worker Thread " << GetCurrentThreadId() << #else " Worker Thread " << pthread_self() << #endif ":" << endl << "---------------------------------------" "-------------------" << endl; cout << oss.str(); cout.flush(); report = true; reported = true; } } // @bug2099- #endif } #ifdef PROFILE Stats::stopParseEvent(WE_STATS_WAIT_TO_SELECT_COL); #endif // Have obtained the table and column for parsing. // Start parsing the column data. double processingTime; int rc = fTableInfo[tableId].parseColumn(columnId,myParseBuffer, processingTime); if(rc != NO_ERROR) { // Error occurred while parsing the data, break out of loop. BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; oss << "Bulkload Parse (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << " during parsing. Terminating this job."; fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); fLog.logMsg( oss.str(), rc, MSGLVL_CRITICAL ); setParseErrorOnTable( tableId, true ); return; } // Parsing is complete. Acquire the mutex and increment // the parsingComplete value for the buffer if(fTableInfo[tableId].getStatusTI() != WriteEngine::ERR) { #ifdef PROFILE Stats::startParseEvent(WE_STATS_WAIT_TO_COMPLETE_PARSE); #endif boost::mutex::scoped_lock lock(fParseMutex); #ifdef PROFILE Stats::stopParseEvent(WE_STATS_WAIT_TO_COMPLETE_PARSE); Stats::startParseEvent(WE_STATS_COMPLETING_PARSE); #endif rc = fTableInfo[tableId].setParseComplete(columnId, myParseBuffer, processingTime); if (rc != NO_ERROR) { BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; oss << "Bulkload Parse (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << " during parse completion. Terminating this job."; fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); fLog.logMsg( oss.str(), rc, MSGLVL_CRITICAL ); setParseErrorOnTable( tableId, false ); return; } #ifdef PROFILE Stats::stopParseEvent(WE_STATS_COMPLETING_PARSE); #endif } } } catch (SecondaryShutdownException& ex) { // We are bailing out because another thread set bad job status ostringstream oss; if (tableId != -1) { oss << "Bulkload Parse (thread " << id << ") Stopped parsing Table " << fTableInfo[tableId].getTableName() << ". " << ex.what(); setParseErrorOnTable( tableId, true ); } else { oss << "Bulkload Parse (thread " << id << ") Stopped parsing Tables. " << ex.what(); } fLog.logMsg( oss.str(), MSGLVL_INFO1 ); } catch (exception& ex) { BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; if (tableId != -1) { oss << "Bulkload Parse (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << ". " << ex.what() << ". Terminating this job."; setParseErrorOnTable( tableId, true ); fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); } else { oss << "Bulkload Parse (thread " << id << ") Failed for Table. " << ex.what() << ". Terminating this job."; } fLog.logMsg( oss.str(), ERR_UNKNOWN, MSGLVL_CRITICAL ); } catch (...) { BulkStatus::setJobStatus( EXIT_FAILURE ); ostringstream oss; if (tableId != -1) { oss << "Bulkload Parse (thread " << id << ") Failed for Table " << fTableInfo[tableId].getTableName() << ". Terminating this job."; setParseErrorOnTable( tableId, true ); fTableInfo[tableId].fBRMReporter.addToErrMsgEntry(oss.str()); } else { oss << "Bulkload Parse (thread " << id << ") Failed for Table. Terminating this job."; } fLog.logMsg( oss.str(), ERR_UNKNOWN, MSGLVL_CRITICAL ); } } //------------------------------------------------------------------------------ // Search for an available table/column/buffer to be parsed. // First available table/column/buffer that is found, is locked and assigned to // the specified thread id. // Return value is -1 if no table/column/buffer is available for parsing. //------------------------------------------------------------------------------ // @bug2099 - Temp hack to diagnose deadlock. Added report parm and couts below. bool BulkLoad::lockColumnForParse( int thrdId, int & tableId, int & columnId, int & myParseBuffer, bool report) { // Acquire mutex // Iterate on the table list // Check if the currentParseBuffer is available for parsing // If yes, put the locker and fill the tableId and columnId // else, go to the next table for checking if a column is available boost::mutex::scoped_lock lock(fParseMutex); for(unsigned i=0; i