/* Copyright (C) 2014 InfiniDB, Inc. Copyright (C) 2016 MariaDB Corporation 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: columnstoreDB.cpp 419 2007-07-22 17:18:00Z dhill $ * ******************************************************************************************/ /** * @file */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "liboamcpp.h" #include "configcpp.h" #include "installdir.h" #include "mcsconfig.h" using namespace std; using namespace oam; using namespace config; #include "calpontsystemcatalog.h" using namespace execplan; namespace { void usage(char* prog) { cout << endl; cout << "Usage: " << prog << " [options]" << endl; cout << endl; cout << "This utility is used to suspend and resume Columnstore Database Writes." << endl; cout << "Normally this would be done while performing Database Backups and" << endl; cout << "Restores " << endl; cout << endl; cout << "Options:" << endl; cout << "-c Command: suspend or resume" << endl << endl; cout << "-h Display this help." << endl << endl; } } // namespace /****************************************************************************************** * @brief DisplayLockedTables * * purpose: Show the details of all the locks in tableLocks * Used when attempting to suspend or stop the * database, but there are table locks. * ******************************************************************************************/ void DisplayLockedTables(std::vector& tableLocks, BRM::DBRM* pDBRM) { cout << "The following tables are locked:" << endl; // Initial widths of columns to display. We pass thru the table // and see if we need to grow any of these. unsigned int lockIDColumnWidth = 6; // "LockID" unsigned int tableNameColumnWidth = 12; // "Name" unsigned int ownerColumnWidth = 7; // "Process" unsigned int pidColumnWidth = 3; // "PID" unsigned int sessionIDColumnWidth = 7; // "Session" unsigned int createTimeColumnWidth = 12; // "CreationTime" unsigned int dbrootColumnWidth = 7; // "DBRoots" unsigned int stateColumnWidth = 9; // "State" // Initialize System Catalog object used to get table name boost::shared_ptr systemCatalogPtr = execplan::CalpontSystemCatalog::makeCalpontSystemCatalog(0); std::string fullTblName; const char* tableState; // Make preliminary pass through the table locks in order to determine our // output column widths based on the data. Min column widths are based on // the width of the column heading (except for the 'state' column). uint64_t maxLockID = 0; uint32_t maxPID = 0; int32_t maxSessionID = 0; int32_t minSessionID = 0; std::vector createTimes; std::vector pms; char cTimeBuffer[64]; execplan::CalpontSystemCatalog::TableName tblName; for (unsigned idx = 0; idx < tableLocks.size(); idx++) { if (tableLocks[idx].id > maxLockID) { maxLockID = tableLocks[idx].id; } try { tblName = systemCatalogPtr->tableName(tableLocks[idx].tableOID); } catch (...) { tblName.schema.clear(); tblName.table.clear(); } fullTblName = tblName.toString(); if (fullTblName.size() > tableNameColumnWidth) { tableNameColumnWidth = fullTblName.size(); } if (tableLocks[idx].ownerName.length() > ownerColumnWidth) { ownerColumnWidth = tableLocks[idx].ownerName.length(); } if (tableLocks[idx].ownerPID > maxPID) { maxPID = tableLocks[idx].ownerPID; } if (tableLocks[idx].ownerSessionID > maxSessionID) { maxSessionID = tableLocks[idx].ownerSessionID; } if (tableLocks[idx].ownerSessionID < minSessionID) { minSessionID = tableLocks[idx].ownerSessionID; } // Creation Time. // While we're at it, we save the time string off into a vector // so we can display it later without recalcing it. struct tm timeTM; localtime_r(&tableLocks[idx].creationTime, &timeTM); ctime_r(&tableLocks[idx].creationTime, cTimeBuffer); strftime(cTimeBuffer, 64, "%F %r:", &timeTM); cTimeBuffer[strlen(cTimeBuffer) - 1] = '\0'; // strip trailing '\n' std::string cTimeStr(cTimeBuffer); if (cTimeStr.length() > createTimeColumnWidth) { createTimeColumnWidth = cTimeStr.length(); } createTimes.push_back(cTimeStr); } tableNameColumnWidth += 1; ownerColumnWidth += 1; createTimeColumnWidth += 1; std::ostringstream idString; idString << maxLockID; if (idString.str().length() > lockIDColumnWidth) lockIDColumnWidth = idString.str().length(); lockIDColumnWidth += 1; std::ostringstream pidString; pidString << maxPID; if (pidString.str().length() > pidColumnWidth) pidColumnWidth = pidString.str().length(); pidColumnWidth += 1; const std::string sessionNoneStr("BulkLoad"); std::ostringstream sessionString; sessionString << maxSessionID; if (sessionString.str().length() > sessionIDColumnWidth) sessionIDColumnWidth = sessionString.str().length(); if ((minSessionID < 0) && (sessionNoneStr.length() > sessionIDColumnWidth)) sessionIDColumnWidth = sessionNoneStr.length(); sessionIDColumnWidth += 1; // write the column headers before the first entry cout.setf(ios::left, ios::adjustfield); cout << setw(lockIDColumnWidth) << "LockID" << setw(tableNameColumnWidth) << "Name" << setw(ownerColumnWidth) << "Process" << setw(pidColumnWidth) << "PID" << setw(sessionIDColumnWidth) << "Session" << setw(createTimeColumnWidth) << "CreationTime" << setw(stateColumnWidth) << "State" << setw(dbrootColumnWidth) << "DBRoots" << endl; for (unsigned idx = 0; idx < tableLocks.size(); idx++) { try { tblName = systemCatalogPtr->tableName(tableLocks[idx].tableOID); } catch (...) { tblName.schema.clear(); tblName.table.clear(); } fullTblName = tblName.toString(); cout << setw(lockIDColumnWidth) << tableLocks[idx].id << setw(tableNameColumnWidth) << fullTblName << setw(ownerColumnWidth) << tableLocks[idx].ownerName << setw(pidColumnWidth) << tableLocks[idx].ownerPID; // Log session ID, or "BulkLoad" if session is -1 if (tableLocks[idx].ownerSessionID < 0) cout << setw(sessionIDColumnWidth) << sessionNoneStr; else cout << setw(sessionIDColumnWidth) << tableLocks[idx].ownerSessionID; // Creation Time cout << setw(createTimeColumnWidth) << createTimes[idx]; // Processor State if (pDBRM && !pDBRM->checkOwner(tableLocks[idx].id)) { tableState = "Abandoned"; } else { tableState = ((tableLocks[idx].state == BRM::LOADING) ? "LOADING" : "CLEANUP"); } cout << setw(stateColumnWidth) << tableState; // PM List cout << setw(dbrootColumnWidth); for (unsigned k = 0; k < tableLocks[idx].dbrootList.size(); k++) { if (k > 0) cout << ','; cout << tableLocks[idx].dbrootList[k]; } cout << endl; } // end of loop through table locks } int main(int argc, char** argv) { string command; Oam oam; BRM::DBRM dbrm; signed char c; // Invokes member function `int operator ()(void);' while ((c = getopt(argc, argv, "c:h")) != -1) { switch (c) { case 'c': command = optarg; break; case 'h': usage(argv[0]); exit(-1); break; default: usage(argv[0]); exit(1); break; } } if (command == "suspend") { try { std::vector tableLocks = dbrm.getAllTableLocks(); if (!tableLocks.empty()) { DisplayLockedTables(tableLocks, &dbrm); } else { dbrm.setSystemSuspended(true); sleep(5); string cmd = "save_brm > " + string(MCSLOGDIR) + "/save_brm.log1 2>&1"; int rtnCode = system(cmd.c_str()); if (rtnCode == 0) { cout << endl << "Suspend Columnstore Database Writes Request successfully completed" << endl; } else { cout << endl << "Suspend Columnstore Database Writes Failed: save_brm Failed" << endl; dbrm.setSystemSuspended(false); } } } catch (exception& e) { cout << endl << "**** Suspend Columnstore Database Writes Failed: " << e.what() << endl; } catch (...) { cout << endl << "**** Suspend Columnstore Database Writes Failed" << endl; } } else { if (command == "resume") { try { dbrm.setSystemSuspended(false); cout << endl << "Resume Columnstore Database Writes Request successfully completed" << endl; } catch (exception& e) { cout << endl << "**** Resume Columnstore Database Writes Failed: " << e.what() << endl; } catch (...) { cout << endl << "**** Resume Columnstore Database Writes Failed" << endl; } } else { cout << "Invalid Command Entered, please try again" << endl; exit(-1); } } exit(0); }