/* 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_bulkrollbackmgr.cpp 4737 2013-08-14 20:45:46Z bwilkinson $ */ #include #include #include #include #include #include #include #include #include #include #include #include "we_bulkrollbackmgr.h" #include "we_define.h" #include "we_brm.h" #include "we_config.h" #include "we_fileop.h" #include "we_log.h" #include "we_bulkrollbackfile.h" #include "we_bulkrollbackfilecompressed.h" #include "we_bulkrollbackfilecompressedhdfs.h" #include "we_rbmetawriter.h" #include "messageids.h" #include "cacheutils.h" using namespace execplan; #include "IDBPolicy.h" using namespace idbdatafile; using namespace std; namespace { const char* DATA_DIR_SUFFIX = "_data"; const char* TMP_FILE_SUFFIX = ".tmp"; const int BUF_SIZE = 1024; // size of buffer used to read meta data records const std::string DB_FILE_PREFIX ("FILE"); const std::string DB_FILE_EXTENSION(".cdf"); const std::string DB_FILE_EXTENSION_ORIG(".orig"); const std::string DB_FILE_EXTENSION_TMP (".tmp" ); } namespace WriteEngine { //------------------------------------------------------------------------------ // BulkRollbackMgr constructor // // tableOID - OID of the table to be rolled back. //------------------------------------------------------------------------------ BulkRollbackMgr::BulkRollbackMgr ( OID tableOID, uint64_t lockID, const std::string& tableName, const std::string& applName, Log* logger ) : fTableOID(tableOID), fLockID(lockID), fTableName(tableName), fProcessId(0), fMetaFile(NULL), fPendingDctnryStoreOID(0), fPendingDctnryStoreDbRoot(0), fSysLogger( logging::LoggingID( SUBSYSTEM_ID_WE ) ), fDebugConsole( false ), fLog(logger), fApplName(applName), fVersion(4) { } //------------------------------------------------------------------------------ // Rolls back the state of the extentmap and database files for the table OID // specified to the constructor, using the previously written meta-data file. // The requiredMetaFile flag indicates whether a missing bulk rollback file // should be considered an error or not; should probably only be 'true' if // rolling back during a failed mode3 import, where we know when a metadata // backup file has been created. // // returns: // NO_ERROR if rollback completed successfully //------------------------------------------------------------------------------ int BulkRollbackMgr::rollback ( bool keepMetaFile ) { logAMessage( logging::LOG_TYPE_INFO, logging::M0084, 0, fApplName ); int rc = NO_ERROR; int dbRootRollbackCount = 0; try { // validate that BRM is in read/write mode so we can update extentmap rc = BRMWrapper::getInstance()->isReadWrite(); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback for table " << fTableName << " (OID-" << fTableOID << ") not performed; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } std::vector dbRoots; Config::getRootIdList( dbRoots ); std::string emptyText0072; logAMessage( logging::LOG_TYPE_INFO, logging::M0072, 0, emptyText0072 ); // Loop through DBRoots for this PM for (unsigned m = 0; m < dbRoots.size(); m++) { std::istringstream metaDataStream; bool bPerformRollback = openMetaDataFile ( dbRoots[m], metaDataStream ); // Call function to: // 1. read bulk rollback meta-data file // 2. rollback applicable extents from extentmap // 3. delete applicable extents from database files // 4. reinitialize blocks trailing the HWM block in the last extent // of each segment file // ... if (bPerformRollback) { dbRootRollbackCount++; deleteExtents ( metaDataStream ); closeMetaDataFile ( ); } else // Skip any DBRoot not having a meta-data file { std::ostringstream msg0090Text; msg0090Text << dbRoots[m]; logAMessage( logging::LOG_TYPE_INFO, logging::M0090, 0, msg0090Text.str() ); } } if (dbRootRollbackCount > 0) { // Notify PrimProc to flush FD cache. If error occurs, we tell // the user but keep going. int flushFd_rc = cacheutils::dropPrimProcFdCache(); if (flushFd_rc != 0) { std::ostringstream oss; oss << "ClearTableLock: Error flushing PrimProc " "FD cache after rolling back data for table " << fTableName << " (OID-" << fTableOID << "); rc-" << flushFd_rc; // If we have a logger, then use it to log to syslog, etc if (fLog) { fLog->logMsg( oss.str(), MSGLVL_ERROR ); } else // log message ourselves { std::cout << oss.str() << std::endl; logging::Message m( logging::M0010 ); logging::Message::Args args; args.add( oss.str() ); m.format( args ); fSysLogger.logErrorMessage( m ); } } // Notify PrimProc to flush block cache. If error occurs, we tell // the user but keep going. std::vector allOIDs; std::set::const_iterator iter = fAllColDctOIDs.begin(); cerr << "Rollback flushing: "; while (iter != fAllColDctOIDs.end()) { cerr << *iter << ", "; //std::cout << "Flushing OID from PrimProc cache " << *iter << // std::endl; allOIDs.push_back(*iter); ++iter; } cerr << endl; int cache_rc = cacheutils::flushOIDsFromCache( allOIDs ); if (cache_rc != 0) { std::ostringstream oss; oss << "ClearTableLock: Error flushing " "PrimProc cache after rolling back data for table " << fTableName << " (OID-" << fTableOID << "); rc-" << cache_rc; // If we have a logger, then use it to log to syslog, etc if (fLog) { fLog->logMsg( oss.str(), MSGLVL_ERROR ); } else // log message ourselves { std::cout << oss.str() << std::endl; logging::Message m( logging::M0010 ); logging::Message::Args args; args.add( oss.str() ); m.format( args ); fSysLogger.logErrorMessage( m ); } } } } catch (WeException& ex) { std::string msgText(fApplName); msgText += ". (rollback failed; "; msgText += ex.what(); msgText += ')'; logAMessage( logging::LOG_TYPE_ERROR, logging::M0085, 0, msgText ); fErrorMsg = ex.what(); return ex.errorCode(); } if (!keepMetaFile) deleteMetaDataFiles ( ); if (dbRootRollbackCount > 0) { logAMessage( logging::LOG_TYPE_INFO, logging::M0085, 0, fApplName ); } else { std::string msgText(fApplName); msgText += ". (Nothing to rollback)"; logAMessage( logging::LOG_TYPE_INFO, logging::M0085, 0, msgText ); } return rc; } //------------------------------------------------------------------------------ // Validate that all the bulk rollback meta files on all the local DBRoots // exist. This should apply for a cpimport.bin mode3 import for example. // A mode1 distributed import on the other hand, might not have gotten far // enough to have created a bulk rollback meta file on every PM, so // validateAllMetaFilesExist() should probably only be called within the // context of a mode3 import that has entered rollback mode. In any other // case, a missing bulk rollback meta file might be explainable. // // @bug 4496 3.0 Failover // NOTE: Stopped using this function with 3.0, when it became possible for // DBRoots to move from 1 PM to another, in the middle of the job. // We simply perform a bulk rollback for any meta-data file we find, // and skip performing a bulk rollback for a dbroot that does not // have a meta-data file. Kept the function around for the time being. //------------------------------------------------------------------------------ void BulkRollbackMgr::validateAllMetaFilesExist ( const std::vector& dbRoots ) const { // Loop through DBRoots for this PM for (unsigned m = 0; m < dbRoots.size(); m++) { std::string bulkRollbackPath( Config::getDBRootByNum(dbRoots[m]) ); // Construct file name and check for it's existence std::ostringstream oss; oss << '/' << DBROOT_BULK_ROLLBACK_SUBDIR << '/' << fTableOID; std::string metaFileName = bulkRollbackPath; metaFileName += oss.str(); if ( !IDBPolicy::exists( metaFileName.c_str() ) ) { std::ostringstream oss; oss << "Error opening bulk rollback meta-data file " << metaFileName << "; File does not exist."; throw WeException( oss.str(), ERR_FILE_OPEN ); } } } //------------------------------------------------------------------------------ // Open the meta-data file for fTableOID. File contains information used in // rolling back the table to a previous state. // Returns true/false to indicate whether execution should continue if the // meta-data file is missing. //------------------------------------------------------------------------------ bool BulkRollbackMgr::openMetaDataFile ( uint16_t dbRoot, std::istringstream& metaDataStream ) { std::string bulkRollbackPath( Config::getDBRootByNum( dbRoot ) ); // Construct file name and check for it's existence std::ostringstream oss; oss << '/' << DBROOT_BULK_ROLLBACK_SUBDIR << '/' << fTableOID; fMetaFileName = bulkRollbackPath; fMetaFileName += oss.str(); // Return if the meta-data file does not exist. This could happen if we // are executing distributed rollback on several PMs, some of which may // have not even executed an import. // Also could happen if DBRoots are moved from 1 PM to another during a job. if ( !IDBPolicy::exists( fMetaFileName.c_str() ) ) { return false; } // Open the file fMetaFile = IDBDataFile::open( IDBPolicy::getType(fMetaFileName.c_str(), IDBPolicy::WRITEENG), fMetaFileName.c_str(), "rb", 0); if ( !fMetaFile ) { int errRc = errno; std::ostringstream oss; oss << "Error opening bulk rollback meta-data file " << fMetaFileName << "; err-" << errRc << "; " << strerror( errRc ); throw WeException( oss.str(), ERR_FILE_OPEN ); } fMetaFileNames.push_back( fMetaFileName ); // First record in the file must be a Version record. char inBuf[ BUF_SIZE ]; ssize_t metaFileSize = IDBPolicy::size( fMetaFileName.c_str() ); boost::scoped_array buf( new char[ metaFileSize ] ); // retry 10 times for partial reads, just in case ssize_t readSofar = 0; // bytes read so far ssize_t bytes = 0; // bytes read by one pread char* p = buf.get(); for (int i = 0; i < 10 && readSofar < metaFileSize; i++) { bytes = fMetaFile->pread( p + readSofar, readSofar, metaFileSize - readSofar); if (bytes < 0) break; readSofar += bytes; } if ( readSofar != metaFileSize ) { int errRc = errno; std::ostringstream oss; oss << "Error reading bulk rollback meta-data file " << fMetaFileName << "; read/expect:" << readSofar << "/" << metaFileSize << "; err-" << errRc << "; " << strerror( errRc ); throw WeException( oss.str(), ERR_FILE_READ ); } // put the data in a string stream metaDataStream.str( string( p, metaFileSize ) ); buf.reset(); // read data metaDataStream.getline( inBuf, BUF_SIZE ); if (RBMetaWriter::verifyVersion3(inBuf)) { fVersion = 3; } else if (RBMetaWriter::verifyVersion4(inBuf)) { fVersion = 4; } else { std::ostringstream oss; oss << "Invalid version record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } return true; } //------------------------------------------------------------------------------ // Close the current meta-data file used in rolling back fTableOID. //------------------------------------------------------------------------------ void BulkRollbackMgr::closeMetaDataFile ( ) { delete fMetaFile; fMetaFile = NULL; } //------------------------------------------------------------------------------ // Delete all the local meta-data files used in rolling back fTableOID. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteMetaDataFiles ( ) { for (unsigned k = 0; k < fMetaFileNames.size(); k++) { IDBPolicy::remove( fMetaFileNames[k].c_str() ) ; // Unlink corresponding tmp file created by RBMetaWriter. std::string tmpMetaFileName = fMetaFileNames[k]; tmpMetaFileName += TMP_FILE_SUFFIX; IDBPolicy::remove( tmpMetaFileName.c_str() ); deleteSubDir( fMetaFileNames[k] ); } } //------------------------------------------------------------------------------ // Delete the subdirectory used to backup data needed for rollback. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteSubDir( const std::string& metaFileName ) { std::string bulkRollbackSubPath( metaFileName ); bulkRollbackSubPath += DATA_DIR_SUFFIX; if ( IDBPolicy::remove( bulkRollbackSubPath.c_str() ) != 0 ) { std::ostringstream oss; oss << "Warning: Error deleting bulk rollback data subdirectory " << bulkRollbackSubPath << ";"; if (fLog) fLog->logMsg( oss.str(), MSGLVL_WARNING ); else std::cout << oss.str() << std::endl; } } //------------------------------------------------------------------------------ // Function that drives the rolling back or deletion of extents for a given // database table as specified in a meta-data bulk rollback file. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteExtents ( std::istringstream& metaDataStream ) { char inBuf[ BUF_SIZE ]; OID columnOID = 0; OID storeOID = 0; uint32_t dbRoot = 0; // Loop through the records in the meta-data file while (metaDataStream.getline( inBuf, BUF_SIZE )) { // Restore extents for a DBRoot if (RBMetaWriter::verifyColumn1Rec(inBuf)) { // Process any pending dictionary deletes if (fPendingDctnryExtents.size() > 0) { deleteDctnryExtents ( ); deleteDbFiles( ); } deleteColumn1Extents ( inBuf ); deleteDbFiles( ); } // Delete all extents from a formerly empty DBRoot else if (RBMetaWriter::verifyColumn2Rec(inBuf)) { // Process any pending dictionary deletes if (fPendingDctnryExtents.size() > 0) { deleteDctnryExtents ( ); deleteDbFiles( ); } deleteColumn2Extents ( inBuf ); deleteDbFiles( ); } else if (RBMetaWriter::verifyDStore1Rec(inBuf) || RBMetaWriter::verifyDStore2Rec(inBuf)) { if (fPendingDctnryExtents.size() > 0) { char recType[100]; int numFields = sscanf( inBuf, "%s %u %u %d", recType, &columnOID, &storeOID, &dbRoot ); if (numFields != 4) { std::ostringstream oss; oss << "Invalid record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } // Process any pending dictionary deletes if ((storeOID != fPendingDctnryStoreOID) || (dbRoot != fPendingDctnryStoreDbRoot)) { deleteDctnryExtents ( ); deleteDbFiles( ); } } readMetaDataRecDctnry ( inBuf ); } else { // ignore unrecognized record type } } // end of loop through all the records in the meta-data input file // Process any pending dictionary deletes if (fPendingDctnryExtents.size() > 0) { deleteDctnryExtents ( ); deleteDbFiles( ); } } //------------------------------------------------------------------------------ // Read a meta-data dictionary record (DSTORE1 or DSTORE2) from meta-data file. // Each record specifies the rollback point for a given dbroot, partition, // segment number, and HWM for a certain dictionary store OID. // // inBuf - latest dictionary extent record to be parsed from meta-data file //------------------------------------------------------------------------------ void BulkRollbackMgr::readMetaDataRecDctnry ( const char* inBuf ) { char recType[100]; OID dColumnOID; OID dStoreOID; uint32_t dbRootHwm; uint32_t partNumHwm; uint32_t segNumHwm; HWM localHwm; int compressionType = 0; // optional parameter sscanf(inBuf, "%s", recType); RollbackData rbData; // Process DSTORE1 records representing segment files with an HWM if (RBMetaWriter::verifyDStore1Rec(recType)) { int numFields = sscanf(inBuf, "%s %u %u %u %u %u %u %d", recType, &dColumnOID, &dStoreOID, &dbRootHwm, &partNumHwm, &segNumHwm, &localHwm, &compressionType ); if (numFields < 7) // compressionType optional { std::ostringstream oss; oss << "Invalid DSTOR1 record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } rbData.fWithHwm = true; rbData.fHwm = localHwm; } // Process DSTORE2 records representing segment files w/o HWM; meaning that // segment file did not previously exist and can be deleted if it was added else { int numFields = sscanf(inBuf, "%s %u %u %u %u %u %d", recType, &dColumnOID, &dStoreOID, &dbRootHwm, &partNumHwm, &segNumHwm, &compressionType ); if (numFields < 6) // compressionType optional { std::ostringstream oss; oss << "Invalid DSTOR2 record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } rbData.fWithHwm = false; rbData.fHwm = 0; } rbData.fDbRoot = dbRootHwm; rbData.fPartNum = partNumHwm; rbData.fSegNum = segNumHwm; fPendingDctnryExtents.push_back( rbData ); // OID and compression type should be the same for all store files relating // to the same dictionary column, but they are set for each record nonethe- // less since the format of the meta data file is a flat file format. // Likewise, the DBRoot will be the same for each collection of dictionary // extents that are processed as a group. fPendingDctnryStoreOID = dStoreOID; fPendingDctnryStoreCompressionType = compressionType; fPendingDctnryStoreDbRoot = dbRootHwm; } //------------------------------------------------------------------------------ // Delete column extents based on COLUMN1 record input //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteColumn1Extents ( const char* inBuf ) { if (fVersion == 3) deleteColumn1ExtentsV3( inBuf ); else deleteColumn1ExtentsV4( inBuf ); } //------------------------------------------------------------------------------ // Delete column extents based on COLUMN2 record input //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteColumn2Extents ( const char* inBuf ) { if (fVersion == 3) deleteColumn2ExtentsV3( inBuf ); else deleteColumn2ExtentsV4( inBuf ); } //------------------------------------------------------------------------------ // Delete all the column extents (from the extent map and the db files) that // logically follow the HWM extent contained in inBuf; where inBuf is a // COLUMN1 record read from a meta-data bulk rollback file. This function // is limited to rolling back the extent changes to a specific DBRoot. // // inBuf - latest column extent record to be parsed from meta-data file // // This function exists to handle version3 metadata input files, in case a user: // 1. ungracefully took their system down with a table lock in place // 2. upgraded to a release that supported version4 (used to support the new // segment file numbering). // 3. then brought infinidb up, and DMLProc triggered this function to execute // a bulk rollback (during system startup) using a leftover version3 // formatted meta data file. // // In the case of a COLUMN1 record, V3 and V4 are handled the same, so this // adaptor function is a pass-thru to the V4 function. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteColumn1ExtentsV3 ( const char* inBuf ) { deleteColumn1ExtentsV4( inBuf ); } //------------------------------------------------------------------------------ // Delete all the column extents (from the extent map and the db files) that // fall in a certain DBRoot; restoring the DBRoot to an "empty" state. inBuf // is a COLUMN2 record read from a meta-data bulk rollback file. This function // is limited to rolling back the extent changes to a specific DBRoot. // // inBuf - latest column extent record to be parsed from meta-data file // // This function exists to handle version3 metadata input files, in case a user: // 1. ungracefully took their system down with a table lock in place // 2. upgraded to a release that supported version4 (used to support the new // segment file numbering). // 3. then brought infinidb up, and DMLProc triggered this function to execute // a bulk rollback (during system startup) using a leftover version3 // formatted meta data file. // // With Version3, we always wrote the expected starting segment number for an // empty DBRoot, in a COLUMN2 record. With Version4, we always write a 0 for // the starting segment number, because the starting segment number is undeter- // mined. So this adaptor function changes any segment number for the COLUMN2 // record to a 0, to be 100% compatible with the Version4 format. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteColumn2ExtentsV3 ( const char* inBuf ) { char recType[100]; OID columnOID; uint32_t dbRootHwm; uint32_t partNumHwm; uint32_t segNumHwm; int colTypeInt; char colTypeName[100]; uint32_t colWidth; int compressionType = 0; // optional parameter // Read meta-data record int numFields = sscanf(inBuf, "%s %u %u %u %u %d %s %u %d", recType, &columnOID, &dbRootHwm, &partNumHwm, &segNumHwm, &colTypeInt, colTypeName, &colWidth, &compressionType ); if (numFields < 8) // compressionType is optional { std::ostringstream oss; oss << "Invalid COLUM2 record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } std::ostringstream revisedBuf; uint32_t revisedSegNumHwm = 0; revisedBuf << recType << ' ' << columnOID << ' ' << dbRootHwm << ' ' << partNumHwm << ' ' << revisedSegNumHwm << ' ' << colTypeInt << ' ' << colTypeName << ' ' << colWidth << ' '; if (numFields > 8) revisedBuf << compressionType; deleteColumn2ExtentsV4( revisedBuf.str().c_str() ); } //@bug 4091: V4 support for adding DBRoot //------------------------------------------------------------------------------ // Delete all the column extents (from the extent map and the db files) that // logically follow the HWM extent contained in inBuf; where inBuf is a // COLUMN1 record read from a meta-data bulk rollback file. This function // is limited to rolling back the extent changes to a specific DBRoot. // // inBuf - latest column extent record to be parsed from meta-data file //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteColumn1ExtentsV4 ( const char* inBuf ) { char recType[100]; OID columnOID; uint32_t dbRootHwm; uint32_t partNumHwm; uint32_t segNumHwm; HWM lastLocalHwm; int colTypeInt; CalpontSystemCatalog::ColDataType colType; char colTypeName[100]; uint32_t colWidth; int compressionType = 0; // optional parameter // Read meta-data record int numFields = sscanf(inBuf, "%s %u %u %u %u %u %d %s %u %d", recType, &columnOID, &dbRootHwm, &partNumHwm, &segNumHwm, &lastLocalHwm, &colTypeInt, colTypeName, &colWidth, &compressionType ); colType = (CalpontSystemCatalog::ColDataType)colTypeInt; if (numFields < 9) // compressionType is optional { std::ostringstream oss; oss << "Invalid COLUM1 record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } std::ostringstream msg0073Text; msg0073Text << "DBRoot-" << dbRootHwm << " (column extent)"; logAMessage( logging::LOG_TYPE_INFO, logging::M0073, columnOID, msg0073Text.str() ); // Delete extents from the extentmap std::ostringstream msg0074Text; msg0074Text << "Restoring HWM column extent: " << "dbRoot-" << dbRootHwm << "; part#-" << partNumHwm << "; seg#-" << segNumHwm << "; hwm-" << lastLocalHwm; logAMessage( logging::LOG_TYPE_INFO, logging::M0074, columnOID, msg0074Text.str() ); fAllColDctOIDs.insert( columnOID ); // Create the object responsible for restoring the extents in the db files. BulkRollbackFile* fileRestorer = makeFileRestorer(compressionType); boost::scoped_ptr refBulkRollbackFile(fileRestorer); // DMC-We should probably change this to build up a list of BRM changes, // and wait to make the call(s) to rollback the BRM changes "after" we // have restored the db files, and purged PrimProc FD and block cache. int rc = BRMWrapper::getInstance()->rollbackColumnExtents_DBroot ( columnOID, false, // false -> Don't delete all extents (rollback (uint16_t)dbRootHwm, // to specified dbroot, partition, etc.) partNumHwm, (uint16_t)segNumHwm, lastLocalHwm ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Error rolling back column extents from extent map for " << columnOID << "; dbRoot-" << dbRootHwm << "; partition-" << partNumHwm << "; segment-" << segNumHwm << "; hwm-" << lastLocalHwm << "; " << ec.errorString(rc); throw WeException( oss.str(), ERR_BRM_BULK_RB_COLUMN ); } // Determine the exact rollback point for the extents we are rolling back to const unsigned BLKS_PER_EXTENT = (BRMWrapper::getInstance()->getExtentRows() * colWidth) / BYTE_PER_BLOCK; uint32_t lastBlkOfCurrStripe = 0; uint32_t lastBlkOfPrevStripe = 0; if ((lastLocalHwm + 1) <= BLKS_PER_EXTENT) { lastBlkOfCurrStripe = BLKS_PER_EXTENT - 1; } else { lastBlkOfPrevStripe = lastLocalHwm - (lastLocalHwm % BLKS_PER_EXTENT) - 1; lastBlkOfCurrStripe = lastBlkOfPrevStripe + BLKS_PER_EXTENT; } uint32_t dbRoot = dbRootHwm; uint32_t partNum = partNumHwm; std::string segFileListErrMsg; // Delete extents from the database files. // Loop through all partitions (starting with the HWM partition partNumHwm), // deleting or restoring applicable extents. We stay in loop till we // reach a partition that has no column segment files to roll back. bool useHdfs = IDBPolicy::useHdfs(); while ( 1 ) { std::vector segList; std::string dirName; rc = fileRestorer->buildDirName( columnOID, dbRoot, partNum, dirName ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error constructing path for column " << columnOID << "; dbRoot-" << dbRoot << "; partition-" << partNum << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } rc = getSegFileList( dirName, useHdfs, segList, segFileListErrMsg ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error for column " << columnOID << "; directory-" << dirName << "; " << segFileListErrMsg << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } if (segList.size() == 0) break; // Exit loop when we reach empty partition for (unsigned int kk = 0; kk < segList.size(); kk++) { uint32_t segNum = segList[kk]; if ( partNum == partNumHwm ) { // Don't rollback an OutOfService extent in the HWM partition bool bFound; int extState; rc = BRMWrapper::getInstance()->getExtentState( columnOID, partNum, segNum, bFound, extState ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error for column " << columnOID << "; Unable to get extent state for part-" << partNum << "; seg-" << segNum << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } if ((bFound) && (extState == BRM::EXTENTOUTOFSERVICE)) continue; if ( segNum < segNumHwm ) { fileRestorer->truncateSegmentFile ( columnOID, dbRoot, partNum, segNum, (lastBlkOfCurrStripe + 1) ); } // end of (segNum < segNumHwm) else if ( segNum > segNumHwm ) { if (lastBlkOfPrevStripe > 0) { fileRestorer->truncateSegmentFile ( columnOID, dbRoot, partNum, segNum, (lastBlkOfPrevStripe + 1) ); } // lastBlkOfPrevStripe = 0, means there was no previous // stripe in this partition. The HWM block was in the // first stripe. In this case we can delete any segment // files added to this partition that follow segNumHwm. else { std::string segFileName; fileRestorer->buildSegmentFileName ( columnOID, true, // column segment file dbRoot, partNum, segNum, segFileName ); createFileDeletionEntry( columnOID, true, // column segment file dbRoot, partNum, segNum, segFileName ); } } // end of (segNum > segNumHwm) else // segNum == segNumHwm { if (lastBlkOfCurrStripe == lastLocalHwm) { fileRestorer->truncateSegmentFile ( columnOID, dbRoot, partNum, segNum, (lastBlkOfCurrStripe + 1) ); } else { bool restoreChunk = fileRestorer->doWeReInitExtent(columnOID, dbRoot, partNum, segNum); // For compressed data, if there is no backup chunk to // restore (restoreChunk is false), we still restore // the compressed headers to their previous setting. // This would happen if DBRoot HWM was not on full ex- // tent boundary when it was moved. If/when cpimport // reaches this migrated DBRoot in the middle of an // import, we do not create a backup chunk file. We // instead only fill-in the HWM extent with empty row // markers. So no backup and restore is necessary. Only // need to truncate any extra extents that were added. // Reinit last extent and truncate the remainder, // starting with the next block following the HWM block. fileRestorer->reInitTruncColumnExtent ( columnOID, dbRoot, partNum, segNum, (lastLocalHwm + 1), (lastBlkOfCurrStripe - lastLocalHwm), colType, colWidth, restoreChunk ); } } // end of (segNum == segNumHwm) } else // ( partNum > partNumHwm ) { // Delete any files added to subsequent partitions std::string segFileName; fileRestorer->buildSegmentFileName ( columnOID, true, // column segment file dbRoot, partNum, segNum, segFileName ); createFileDeletionEntry( columnOID, true, // column segment file dbRoot, partNum, segNum, segFileName ); } } // loop thru all the potential segment files in a partition partNum++; } // end of loop to go thru all partitions till we find last segment file } //@bug 4091: V4 support for adding DBRoot //------------------------------------------------------------------------------ // Delete all the column extents (from the extent map and the db files) that // fall in a certain DBRoot; restoring the DBRoot to an "empty" state. inBuf // is a COLUMN2 record read from a meta-data bulk rollback file. This function // is limited to rolling back the extent changes to a specific DBRoot. // // inBuf - latest column extent record to be parsed from meta-data file //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteColumn2ExtentsV4 ( const char* inBuf ) { char recType[100]; OID columnOID; uint32_t dbRootHwm; uint32_t partNumHwm; uint32_t segNumHwm; HWM lastLocalHwm = 0; int colTypeInt; char colTypeName[100]; uint32_t colWidth; int compressionType = 0; // optional parameter // Read meta-data record int numFields = sscanf(inBuf, "%s %u %u %u %u %d %s %u %d", recType, &columnOID, &dbRootHwm, &partNumHwm, &segNumHwm, &colTypeInt, colTypeName, &colWidth, &compressionType ); if (numFields < 8) // compressionType is optional { std::ostringstream oss; oss << "Invalid COLUM2 record in meta-data file " << fMetaFileName << "; record-<" << inBuf << ">" << std::endl; throw WeException( oss.str(), ERR_INVALID_PARAM ); } std::ostringstream msg0073Text; msg0073Text << "DBRoot-" << dbRootHwm << " (column extent)"; logAMessage( logging::LOG_TYPE_INFO, logging::M0073, columnOID, msg0073Text.str() ); // @bug 5644 - If user dropped all partitions in a dbroot, partNumHwm will // be 0, but we may start importing into part# > 0 (to line up with other // DBRoots). Use extent map to find first partition added by this import. std::vector extEntries; int rc = BRMWrapper::getInstance()->getExtents_dbroot( columnOID, extEntries, dbRootHwm ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Error getting extent list from extent map for " << columnOID << "; dbRoot-" << dbRootHwm << "; " << ec.errorString(rc); throw WeException( oss.str(), ERR_BRM_BULK_RB_COLUMN ); } uint32_t part1 = partNumHwm; // lowest part# for column and DBRoot if (extEntries.size() > 0) { part1 = extEntries[0].partitionNum; for (unsigned int kk = 0; kk < extEntries.size(); kk++) { if (extEntries[kk].partitionNum < part1) part1 = extEntries[kk].partitionNum; } } // Delete extents from the extentmap std::ostringstream msg0074Text; msg0074Text << "Restoring empty DBRoot. " "dbRoot-" << dbRootHwm << "; part#-" << partNumHwm << "; seg#-" << segNumHwm << "; hwm-" << lastLocalHwm << "; delete starting at part#-" << part1; logAMessage( logging::LOG_TYPE_INFO, logging::M0074, columnOID, msg0074Text.str() ); fAllColDctOIDs.insert( columnOID ); // Reset partNumHwm to partNum taken from extent map partNumHwm = part1; // Create the object responsible for restoring the extents in the db files. BulkRollbackFile* fileRestorer = makeFileRestorer(compressionType); boost::scoped_ptr refBulkRollbackFile(fileRestorer); // DMC-We should probably change this to build up a list of BRM changes, // and wait to make the call(s) to rollback the BRM changes "after" we // have restored the db files, and purged PrimProc FD and block cache. rc = BRMWrapper::getInstance()->rollbackColumnExtents_DBroot ( columnOID, true, // true -> delete all extents (restore to empty DBRoot) (uint16_t)dbRootHwm, partNumHwm, (uint16_t)segNumHwm, lastLocalHwm ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Error rolling back column extents from extent map for " << columnOID << "; dbRoot-" << dbRootHwm << "; partition-" << partNumHwm << "; segment-" << segNumHwm << "; hwm-" << lastLocalHwm << "; " << ec.errorString(rc); throw WeException( oss.str(), ERR_BRM_BULK_RB_COLUMN ); } uint32_t dbRoot = dbRootHwm; uint32_t partNum = partNumHwm; std::string segFileListErrMsg; // Delete extents from the database files. // Loop through all partitions (starting with the HWM partition partNumHwm), // deleting or restoring applicable extents. We stay in loop till we // reach a partition that has no column segment files to roll back. bool useHdfs = IDBPolicy::useHdfs(); while ( 1 ) { std::vector segList; std::string dirName; rc = fileRestorer->buildDirName( columnOID, dbRoot, partNum, dirName ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error constructing path for column " << columnOID << "; dbRoot-" << dbRoot << "; partition-" << partNum << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } rc = getSegFileList( dirName, useHdfs, segList, segFileListErrMsg ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error for column " << columnOID << "; directory-" << dirName << "; " << segFileListErrMsg << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } if (segList.size() == 0) break; // Exit loop when we reach empty partition for (unsigned int kk = 0; kk < segList.size(); kk++) { uint32_t segNum = segList[kk]; // Delete any files added to subsequent partitions std::string segFileName; fileRestorer->buildSegmentFileName ( columnOID, true, // column segment file dbRoot, partNum, segNum, segFileName ); createFileDeletionEntry( columnOID, true, // column segment file dbRoot, partNum, segNum, segFileName ); } // loop thru all the potential segment files in a partition partNum++; } // end of loop to go thru all partitions till we find last segment file } //------------------------------------------------------------------------------ // Delete dictionary store extents based on COLUMN1 record input //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteDctnryExtents ( ) { if (fVersion == 3) deleteDctnryExtentsV3( ); else deleteDctnryExtentsV4( ); } //------------------------------------------------------------------------------ // Delete all the dictionary store extents (from the extent map and db files) // that logically follow the extents contained in fPendingDctnryExtents; where // fPendingDctnryExtents is a vector of DSTORE1 and DSTORE2 records (for a // specific column OID), read from a meta-data bulk rollback file. This // function is limited to rolling back the extent changes to a specific DBRoot. // // This function exists to handle version3 metadata input files, in case a user: // 1. ungracefully took their system down with a table lock in place // 2. upgraded to a release that supported ersion4 (used to support the new // segment file numbering). // 3. then brought infinidb up, and DMLProc triggered this function to execute // a bulk rollback (during system startup) using a leftover version3 // formatted meta data file. // // With Version3, we always wrote out DSTORE1 record for each existing store // file, and a DSTORE2 record for each store file not present in the relevant // partition. For an empty DBRoot, a DSTORE2 record was written for all the // store files not present in the relevant partition. // With Version4, no trailing DSTORE2 records are written for the store files // not present. A Single DSTORE2 record is still written for an empty DBRoot. // So this adaptor function strips out the unnecessary trailing DSTORE2 // records, to be compatible with the Version4 format. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteDctnryExtentsV3 ( ) { for (unsigned i = 0; i < fPendingDctnryExtents.size(); ++i) { if (!fPendingDctnryExtents[i].fWithHwm) { if (i == 0) { fPendingDctnryExtents[i].fSegNum = 0; fPendingDctnryExtents.resize(1); } else { fPendingDctnryExtents.resize(i); } break; } } deleteDctnryExtentsV4( ); } //@bug 4091: V4 support for adding DBRoot //------------------------------------------------------------------------------ // Delete all the dictionary store extents (from the extent map and db files) // that logically follow the extents contained in fPendingDctnryExtents; where // fPendingDctnryExtents is a vector of DSTORE1 and DSTORE2 records (for a // specific column OID), read from a meta-data bulk rollback file. This // function is limited to rolling back the extent changes to a specific DBRoot. //------------------------------------------------------------------------------ void BulkRollbackMgr::deleteDctnryExtentsV4 ( ) { std::ostringstream msg0073Text; msg0073Text << "DBRoot-" << fPendingDctnryStoreDbRoot << " (dictionary extent)"; logAMessage( logging::LOG_TYPE_INFO, logging::M0073, fPendingDctnryStoreOID, msg0073Text.str() ); if (fPendingDctnryExtents.size() == 0) return; std::vector segNums; std::vector hwms; // Build up list of HWM's to be sent to DBRM for extentmap rollback for (unsigned i = 0; i < fPendingDctnryExtents.size(); i++) { if ( !fPendingDctnryExtents[i].fWithHwm ) break; segNums.push_back( fPendingDctnryExtents[i].fSegNum ); hwms.push_back( fPendingDctnryExtents[i].fHwm ); } // @bug 5644 - If user dropped all partitions in a dbroot, fPartNum will // be 0, but we may start importing into part# > 0 (to line up with other // DBRoots). Use extent map to find first partition added by this import. uint32_t part1 = fPendingDctnryExtents[0].fPartNum; // lowest part# for // OID and DBRoot if (hwms.size() == 0) // empty DBRoot case { std::vector extEntries; int rc = BRMWrapper::getInstance()->getExtents_dbroot( fPendingDctnryStoreOID, extEntries, fPendingDctnryStoreDbRoot ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Error getting extent list from extent map for " << fPendingDctnryStoreOID << "; dbRoot-" << fPendingDctnryStoreDbRoot << "; " << ec.errorString(rc); throw WeException( oss.str(), ERR_BRM_BULK_RB_COLUMN ); } if (extEntries.size() > 0) { part1 = extEntries[0].partitionNum; for (unsigned int kk = 0; kk < extEntries.size(); kk++) { if (extEntries[kk].partitionNum < part1) part1 = extEntries[kk].partitionNum; } } } // Delete extents from the extentmap using hwms vector std::ostringstream msg0074Text; msg0074Text << "Restoring HWM dictionary store extents: " "dbRoot-" << fPendingDctnryStoreDbRoot << "; part#-" << fPendingDctnryExtents[0].fPartNum << "; HWM(s): "; for (unsigned int k = 0; k < hwms.size(); k++) { if (k > 0) msg0074Text << ", "; msg0074Text << hwms[k]; } if (hwms.size() == 0) msg0074Text << "; delete starting at part#-" << part1; logAMessage( logging::LOG_TYPE_INFO, logging::M0074, fPendingDctnryStoreOID, msg0074Text.str() ); fAllColDctOIDs.insert( fPendingDctnryStoreOID ); // Reset partNum to partNum taken from extent map uint32_t partNum = part1; // Create the object responsible for restoring the extents in the db files. BulkRollbackFile* fileRestorer = makeFileRestorer( fPendingDctnryStoreCompressionType); boost::scoped_ptr refBulkRollbackFile(fileRestorer); // DMC-We should probably change this to build up a list of BRM changes, // and wait to make the call(s) to rollback the BRM changes "after" we // have restored the db files, and purged PrimProc FD and block cache. int rc = BRMWrapper::getInstance()->rollbackDictStoreExtents_DBroot ( fPendingDctnryStoreOID, (uint16_t)fPendingDctnryStoreDbRoot, partNum, segNums, hwms ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Error rolling back dictionary extents from extent map for " << fPendingDctnryStoreOID << "; partNum-" << partNum << "; " << ec.errorString(rc); throw WeException( oss.str(), ERR_BRM_BULK_RB_DCTNRY ); } // Assign constants used later in calculating exact rollback point const unsigned COL_WIDTH = 8; const unsigned ROWS_PER_EXTENT = BRMWrapper::getInstance()->getExtentRows(); const unsigned BLKS_PER_EXTENT = (ROWS_PER_EXTENT * COL_WIDTH) / BYTE_PER_BLOCK; uint32_t dbRoot = fPendingDctnryStoreDbRoot; std::string segFileListErrMsg; // Delete extents from the database files. // Loop through all partitions (starting with the HWM partition fPartNum), // deleting or restoring applicable extents. We stay in loop till we // reach a partition that has no dctnry store segment files to roll back. bool useHdfs = IDBPolicy::useHdfs(); while ( 1 ) { std::vector segList; std::string dirName; rc = fileRestorer->buildDirName( fPendingDctnryStoreOID, dbRoot, partNum, dirName ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error constructing path for dictionary " << fPendingDctnryStoreOID << "; dbRoot-" << dbRoot << "; partition-" << partNum << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } rc = getSegFileList( dirName, useHdfs, segList, segFileListErrMsg ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error for dictionary " << fPendingDctnryStoreOID << "; directory-" << dirName << "; " << segFileListErrMsg << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } if (segList.size() == 0) break; for (unsigned int kk = 0; kk < segList.size(); kk++) { uint32_t segNum = segList[kk]; bool reInit = false; uint32_t segIdx = 0; // For each segment file found in dirName, see if the file is in // the list of pending dictionary files to be rolled back; if the // file is found, then roll it back, if not found, then delete it. for (unsigned nn = 0; nn < fPendingDctnryExtents.size(); nn++) { if ((fPendingDctnryExtents[nn].fPartNum == partNum) && (fPendingDctnryExtents[nn].fSegNum == segNum)) { if (fPendingDctnryExtents[nn].fWithHwm) { segIdx = nn; // found corresponding file in pending list reInit = true; } break; } } if (reInit) { // Don't rollback an OutOfService extent in the HWM partition bool bFound; int extState; rc = BRMWrapper::getInstance()->getExtentState( fPendingDctnryStoreOID, partNum, segNum, bFound, extState ); if (rc != NO_ERROR) { WErrorCodes ec; std::ostringstream oss; oss << "Bulk rollback error for dctnry store " << fPendingDctnryStoreOID << "; Unable to get extent state for part-" << partNum << "; seg-" << segNum << "; " << ec.errorString(rc); throw WeException( oss.str(), rc ); } if ((bFound) && (extState == BRM::EXTENTOUTOFSERVICE)) continue; HWM hwm = fPendingDctnryExtents[segIdx].fHwm; // Determine the exact rollback point for the extent // we are rolling back to uint32_t lastBlkOfCurrStripe = hwm - (hwm % BLKS_PER_EXTENT) + BLKS_PER_EXTENT - 1; // Reinit last extent and truncate the remainder, // starting with the next block following the HWM block. fileRestorer->reInitTruncDctnryExtent ( fPendingDctnryStoreOID, dbRoot, partNum, segNum, (hwm + 1), (lastBlkOfCurrStripe - hwm)); } else // don't keep this segment file { std::string segFileName; fileRestorer->buildSegmentFileName ( fPendingDctnryStoreOID, false, // not a column segment file dbRoot, partNum, segNum, segFileName ); createFileDeletionEntry( fPendingDctnryStoreOID, false, // not a column segment file dbRoot, partNum, segNum, segFileName ); } } // loop thru all the potential segment files in a partition partNum++; } //end of loop to go thru all partitions till we find last segment file fPendingDctnryExtents.clear ( ); } //------------------------------------------------------------------------------ // Add specified segment file to the list of files to be deleted. We are // accumulating the list of file names so that they can be deleted in reverse // order. (See deleteDbFiles()). //------------------------------------------------------------------------------ //@bug 4241 Delete files in reverse order void BulkRollbackMgr::createFileDeletionEntry( OID columnOID, bool fileTypeFlag, uint32_t dbRoot, uint32_t partNum, uint32_t segNum, const std::string& segFileName ) { File f; f.oid = columnOID; f.fid = ((fileTypeFlag) ? 1 : 0); // use fid for file type flag f.fPartition = partNum; f.fSegment = segNum; f.fDbRoot = dbRoot; f.fSegFileName = segFileName; fPendingFilesToDelete.push_back( f ); } //------------------------------------------------------------------------------ // Delete db files for a column and DBRoot that are waiting to be deleted. // Files are deleted in reverse order, (see Bug 4241) to facilitate partial // bulk rollback failures and retries. //------------------------------------------------------------------------------ //@bug 4241 Delete files in reverse order void BulkRollbackMgr::deleteDbFiles( ) { // Okay to use a BulkRollbackFile object, because we are only calling the // deleteSegmentFile() method which is a base class function with no // polymorphic behavior. (In other words, we don't need to worry about // employing a BulkRollbackFileCompressed object for a compressed column.) BulkRollbackFile fileRestorer( this ); unsigned int fileCount = fPendingFilesToDelete.size(); for (int i = fileCount - 1; i >= 0; --i) { fileRestorer.deleteSegmentFile( fPendingFilesToDelete[i].oid, ((fPendingFilesToDelete[i].fid > 0) ? true : false), fPendingFilesToDelete[i].fDbRoot, fPendingFilesToDelete[i].fPartition, fPendingFilesToDelete[i].fSegment, fPendingFilesToDelete[i].fSegFileName ); } fPendingFilesToDelete.clear(); } //------------------------------------------------------------------------------ // Get list of segment files found in the specified db directory path. // If bIncludeAlternateSegFileNames is false, then only "FILENNN.cdf" files // will be considered. // If bIncludeAlternateSegFileNames is true, then in addition to "FILENNN.cdf" // files, "FILENNN.cdf.orig" and "FILENNN.cdf.tmp" files will be considered. // The latter case (flag set to true) is used on connection with HDFS. //------------------------------------------------------------------------------ /* static */ int BulkRollbackMgr::getSegFileList( const std::string& dirName, bool bIncludeAlternateSegFileNames, std::vector& segList, std::string& errMsg ) { const unsigned int DB_FILE_PREFIX_LEN = DB_FILE_PREFIX.length(); segList.clear(); std::set segSet; // Return no segment files if partition directory path does not exist if ( !IDBPolicy::isDir( dirName.c_str() ) ) return NO_ERROR; list dircontents; if ( IDBPolicy::listDirectory( dirName.c_str(), dircontents ) == 0 ) { list::iterator iend = dircontents.end(); for ( list::iterator i = dircontents.begin(); i != iend; ++i ) { boost::filesystem::path filepath( *i ); #if BOOST_VERSION >= 105200 //@bug 4989 - stem() and extension() return a temp path object by // value so be sure to store in a string and not a string reference. const std::string fileBase = filepath.stem().generic_string(); const std::string fileExt = filepath.extension().generic_string(); #else const std::string& fileBase = filepath.stem(); const std::string& fileExt = filepath.extension(); #endif //std::cout << "getSegFileList: " << fileBase << " / " << // fileExt << std::endl; // Select files of interest ("FILE*.cdf") bool bMatchFound = false; unsigned int segNumStrLen = 0; if (fileBase.compare(0, DB_FILE_PREFIX_LEN, DB_FILE_PREFIX) == 0) { segNumStrLen = fileBase.length() - DB_FILE_PREFIX_LEN; // Select primary "FILE*.cdf" files if (fileExt == DB_FILE_EXTENSION) { bMatchFound = true; //std::cout << "getSegFileList: match *.cdf" << std::endl; } // Select alternate files of interest ("FILE*.cdf.orig" and // "FILE*.cdf.tmp") used for HDFS backup and rollback. else if (bIncludeAlternateSegFileNames) { if ((fileExt == DB_FILE_EXTENSION_ORIG) || (fileExt == DB_FILE_EXTENSION_TMP)) { //std::cout << "getSegFileList: match *.tmp or *.orig"<< // std::endl; unsigned int extLen = DB_FILE_EXTENSION.length(); if ((fileBase.length() >= extLen) && (fileBase.compare((fileBase.length() - extLen), extLen, DB_FILE_EXTENSION) == 0)) { //std::cout << "getSegFileList: match *cdf.tmp or " // "*cdf.orig" << std::endl; bMatchFound = true; segNumStrLen -= extLen; } } } } // if fileBase.compare() shows filename starting with "FILE" if (bMatchFound) { const std::string& fileSeg = fileBase.substr( DB_FILE_PREFIX_LEN, segNumStrLen); bool bDbFile = true; const unsigned fileSegLen = fileSeg.length(); if (fileSegLen >= 3) { for (unsigned int k = 0; k < fileSegLen; k++) { if ( !isdigit(fileSeg[k]) ) { bDbFile = false; break; } } if (bDbFile) { uint32_t segNum = atoi( fileSeg.c_str() ); segSet.insert( segNum ); } } // filename must have 3 or more digits representing seg number } // found "FILE*.cdf", "FILE*.cdf.orig", or "FILE*.cdf.tmp" file } // for each file in directory if (segSet.size() > 0) { std::set::const_iterator iter = segSet.begin(); while (iter != segSet.end()) { //std::cout << "getSegFileList: Adding segnum " << *iter << // " to the segment list" << std::endl; segList.push_back(*iter); ++iter; } } return NO_ERROR; } // if listDirectory() success else { segList.clear(); errMsg = "Unable to listDirectory in getSegFileList()"; return ERR_BULK_ROLLBACK_SEG_LIST; } } //------------------------------------------------------------------------------ // Make/return the applicable BulkRollbackFile object used to rollback/restore // a db file, based on the compression type and HDFS setting. //------------------------------------------------------------------------------ BulkRollbackFile* BulkRollbackMgr::makeFileRestorer(int compressionType) { BulkRollbackFile* fileRestorer = 0; if (compressionType) { if (IDBPolicy::useHdfs()) fileRestorer = new BulkRollbackFileCompressedHdfs(this); else fileRestorer = new BulkRollbackFileCompressed(this); } else { fileRestorer = new BulkRollbackFile(this); } return fileRestorer; } //------------------------------------------------------------------------------ // Log a message to syslog. columnOID and text are used depending on the msgId. // // logType - type of message (debug, critical, etc) // msgId - message ID // columnOID - column OID associated with this rollback message // text - message text //------------------------------------------------------------------------------ void BulkRollbackMgr::logAMessage ( logging::LOG_TYPE logType, logging::Message::MessageID msgId, OID columnOID, const std::string& text ) { logging::Message m( msgId ); logging::Message::Args args; std::ostringstream ossTbl; ossTbl << fTableName << " (OID-" << fTableOID << ")"; args.add( ossTbl.str() ); if (msgId >= logging::M0073) { switch (msgId) { case logging::M0073: case logging::M0074: case logging::M0075: { args.add( (uint64_t)columnOID ); break; } case logging::M0084: { args.add( (uint64_t)fLockID ); break; } case logging::M0085: { args.add( (uint64_t)fLockID ); break; } case logging::M0090: { // no other arg applicable for this message break; } } args.add( text ); } m.format( args ); // Log to syslog // Note that WARNING, ERROR and CRITICAL are logged to INFO as well as // their respective log files, so that the message will appear in context // with all the other INFO msgs used to track the flow of the rollback. switch (logType) { case logging::LOG_TYPE_DEBUG: { fSysLogger.logDebugMessage( m ); break; } case logging::LOG_TYPE_INFO: { fSysLogger.logInfoMessage( m ); break; } case logging::LOG_TYPE_WARNING: { fSysLogger.logWarningMessage( m ); fSysLogger.logInfoMessage ( m ); break; } case logging::LOG_TYPE_ERROR: { fSysLogger.logErrorMessage( m ); fSysLogger.logInfoMessage ( m ); break; } default: // LOG_TYPE_CRITICAL { fSysLogger.logCriticalMessage( m ); fSysLogger.logInfoMessage ( m ); break; } } // If fLog is defined then log to there, else log to cout. // Currently log msg0074 and msg0075 to console only if debug is enabled switch (msgId) { // Log the name of the table to be rolled back or restored case logging::M0072: { if (fLog) { std::ostringstream oss; oss << "Rolling back extents for table " << fTableName << " (OID-" << fTableOID << ")"; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { std::cout << "Rolling back extents for table " << fTableName << " (OID-" << fTableOID << ")" << std::endl; } break; } // Log the name of the table and column to be rolled back or restored case logging::M0073: { if (fLog) { std::ostringstream oss; oss << "Rolling back extents for table " << fTableName << " (OID-" << fTableOID << "); column " << columnOID << "; " << text; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { std::cout << "Rolling back extents for table " << fTableName << " (OID-" << fTableOID << "); column " << columnOID << "; " << text << std::endl; } break; } // Log the rolling back of extent(s) from the extent map case logging::M0074: { if (fLog) { std::ostringstream oss; oss << "Rolling back extent map for table " << fTableName << " (OID-" << fTableOID << "); column " << columnOID << "; " << text; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { if ( fDebugConsole ) { std::cout << "Rolling back extent map for table " << fTableName << " (OID-" << fTableOID << "); column " << columnOID << "; " << text << std::endl; } } break; } // Log the rolling back of extent(s) from the DB case logging::M0075: { if (fLog) { std::ostringstream oss; oss << "Rolling back db file for table " << fTableName << " (OID-" << fTableOID << "); column " << columnOID << "; " << text; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { if ( fDebugConsole ) { std::cout << "Rolling back db file for table " << fTableName << " (OID-" << fTableOID << "); column " << columnOID << "; " << text << std::endl; } } break; } // Log the start of a bulk rollback case logging::M0084: { if (fLog) { std::ostringstream oss; oss << "Starting bulk rollback for table " << fTableName << " (OID-" << fTableOID << ", Lock-" << fLockID << ") in " << text; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { std::cout << "Starting bulk rollback for table " << fTableName << " (OID-" << fTableOID << ", Lock-" << fLockID << ") in " << text << std::endl; } break; } // Log the end of a bulk rollback case logging::M0085: { if (fLog) { std::ostringstream oss; oss << "Ending bulk rollback for table " << fTableName << " (OID-" << fTableOID << ", Lock-" << fLockID << ") in " << text; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { std::cout << "Ending bulk rollback for table " << fTableName << " (OID-" << fTableOID << ", Lock-" << fLockID << ") in " << text << std::endl; } break; } // Log skipping a DBRoot rollback because no meta-data file case logging::M0090: { if (fLog) { std::ostringstream oss; oss << "Nothing to rollback for table " << fTableName << " (OID-" << fTableOID << ") on DBRoot" << text; fLog->logMsg( oss.str(), MSGLVL_INFO2 ); } else { std::cout << "Nothing to rollback for table " << fTableName << " (OID-" << fTableOID << ") on DBRoot" << text << std::endl; } break; } default: { break; } } } //------------------------------------------------------------------------------ // Standalone utility that can be used to delete bulk rollback files. // WARNING: this function can return an exception (from call to boost // remove_all() ) //------------------------------------------------------------------------------ /* static */ void BulkRollbackMgr::deleteMetaFile( OID tableOID ) { std::vector dbRoots; Config::getRootIdList( dbRoots ); // Loop through DBRoots for this PM for (unsigned m = 0; m < dbRoots.size(); m++) { std::string bulkRollbackPath( Config::getDBRootByNum(dbRoots[m]) ); std::ostringstream oss; oss << '/' << DBROOT_BULK_ROLLBACK_SUBDIR << '/' << tableOID; std::string metaFileName = bulkRollbackPath; metaFileName += oss.str(); // Delete the main bulk rollback file IDBPolicy::remove( metaFileName.c_str() ); // Unlink corresponding tmp file created by RBMetaWriter. std::string tmpMetaFileName = metaFileName; tmpMetaFileName += TMP_FILE_SUFFIX; IDBPolicy::remove( tmpMetaFileName.c_str() ); // Recursively delete any HWM chunk backup files std::string bulkRollbackSubPath( metaFileName ); bulkRollbackSubPath += DATA_DIR_SUFFIX; IDBPolicy::remove( bulkRollbackSubPath.c_str() ); } } } //end of namespace