You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-30 07:25:34 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1466 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1466 lines
		
	
	
		
			54 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: we_rbmetawriter.cpp 4737 2013-08-14 20:45:46Z bwilkinson $
 | ||
| */
 | ||
| 
 | ||
| #include "we_rbmetawriter.h"
 | ||
| 
 | ||
| #include <cerrno>
 | ||
| #include <iostream>
 | ||
| #include <sstream>
 | ||
| #include <unistd.h>
 | ||
| #include <boost/filesystem/path.hpp>
 | ||
| #include <boost/filesystem/convenience.hpp>
 | ||
| 
 | ||
| #include "we_config.h"
 | ||
| #include "we_convertor.h"
 | ||
| #include "we_define.h"
 | ||
| #include "we_log.h"
 | ||
| #include "we_bulkrollbackmgr.h"
 | ||
| #include "idbcompress.h"
 | ||
| using namespace compress;
 | ||
| using namespace execplan;
 | ||
| #include "IDBDataFile.h"
 | ||
| #include "IDBFileSystem.h"
 | ||
| #include "IDBPolicy.h"
 | ||
| using namespace idbdatafile;
 | ||
| 
 | ||
| namespace
 | ||
| {
 | ||
| const char* DATA_DIR_SUFFIX = "_data";
 | ||
| const char* TMP_FILE_SUFFIX = ".tmp";
 | ||
| 
 | ||
| const char* VERSION3_REC    = "# VERSION: 3";
 | ||
| const int   VERSION3_REC_LEN = 12;
 | ||
| const char* VERSION4_REC    = "# VERSION: 4";
 | ||
| const int   VERSION4_REC_LEN = 12;
 | ||
| const char* COLUMN1_REC     = "COLUM1"; // HWM extent for a DBRoot
 | ||
| const int   COLUMN1_REC_LEN = 6;
 | ||
| const char* COLUMN2_REC     = "COLUM2"; // Placeholder for empty DBRoot
 | ||
| const int   COLUMN2_REC_LEN = 6;
 | ||
| const char* DSTORE1_REC     = "DSTOR1"; // HWM extent for a DBRoot
 | ||
| const int   DSTORE1_REC_LEN = 6;
 | ||
| const char* DSTORE2_REC     = "DSTOR2"; // Placeholder for empty DBRoot
 | ||
| const int   DSTORE2_REC_LEN = 6;
 | ||
| 
 | ||
| //--------------------------------------------------------------------------
 | ||
| // Local Function that prints contents of an RBChunkInfo object
 | ||
| //--------------------------------------------------------------------------
 | ||
| std::ostream& operator<<(std::ostream& os,
 | ||
|                          const WriteEngine::RBChunkInfo& chk)
 | ||
| {
 | ||
|     os << "OID-"    << chk.fOid       <<
 | ||
|        "; DBRoot-" << chk.fDbRoot    <<
 | ||
|        "; Part-"   << chk.fPartition <<
 | ||
|        "; Seg-"    << chk.fSegment   <<
 | ||
|        "; HWM-"    << chk.fHwm;
 | ||
| 
 | ||
|     return os;
 | ||
| }
 | ||
| }
 | ||
| 
 | ||
| namespace WriteEngine
 | ||
| {
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Compare function used for set of RBChunkInfo objects.
 | ||
| //------------------------------------------------------------------------------
 | ||
| bool RBChunkInfoCompare::operator()
 | ||
| (const RBChunkInfo& lhs, const RBChunkInfo& rhs) const
 | ||
| {
 | ||
|     if (lhs.fOid < rhs.fOid)
 | ||
|     {
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     if ((lhs.fOid == rhs.fOid) && (lhs.fSegment < rhs.fSegment))
 | ||
|     {
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // RBMetaWriter constructor
 | ||
| //------------------------------------------------------------------------------
 | ||
| RBMetaWriter::RBMetaWriter (
 | ||
|     const std::string& appDesc,
 | ||
|     Log* logger ) : fMetaDataFile(NULL), fAppDesc(appDesc), fLog(logger), fCreatedSubDir(false)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Initialize this meta data file object using the specified table OID and name.
 | ||
| // We assume the application code calling this function, was able to acquire a
 | ||
| // table lock, meaning if there should happen to be any leftoever metadata files
 | ||
| // from a previous job, they can be deleted.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::init (
 | ||
|     OID tableOID,
 | ||
|     const std::string& tableName )
 | ||
| {
 | ||
|     fTableOID  = tableOID;
 | ||
|     fTableName = tableName;
 | ||
| 
 | ||
|     std::vector<uint16_t> dbRoots;
 | ||
|     Config::getRootIdList( dbRoots );
 | ||
| 
 | ||
|     std::string metaFileName;
 | ||
|     std::ostringstream oss;
 | ||
|     oss << "/" << fTableOID;
 | ||
| 
 | ||
|     // Delete any files that collide with the file names we are going to need.
 | ||
|     // Construct the filenames; we will use a temporary file name until we are
 | ||
|     // finished creating, at which time we will rename the temp files.
 | ||
|     for (unsigned m = 0; m < dbRoots.size(); m++)
 | ||
|     {
 | ||
|         std::string bulkRollbackPath( Config::getDBRootByNum( dbRoots[m] ) );
 | ||
|         bulkRollbackPath += '/';
 | ||
|         bulkRollbackPath += DBROOT_BULK_ROLLBACK_SUBDIR;
 | ||
|         metaFileName      = bulkRollbackPath;
 | ||
|         metaFileName     += oss.str();
 | ||
| 
 | ||
|         std::string tmpMetaFileName = metaFileName;
 | ||
|         tmpMetaFileName += TMP_FILE_SUFFIX;
 | ||
| 
 | ||
|         // Delete any files that collide with the filenames we intend to use
 | ||
|         IDBPolicy::remove( metaFileName.c_str() );
 | ||
|         IDBPolicy::remove( tmpMetaFileName.c_str() );
 | ||
| 
 | ||
|         // Clear out any data subdirectory
 | ||
|         deleteSubDir( metaFileName );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Saves snapshot of extentmap into a bulk rollback meta data file, for
 | ||
| // use in a bulk rollback.  Function was closely modeled after function
 | ||
| // of similar name in bulk/we_tableinfo.cpp.  API was modified to help
 | ||
| // facilitate its use by DML.
 | ||
| //
 | ||
| // columns - Column vector with information about column in table.
 | ||
| //           Includes information about the initial HWM extent, so that
 | ||
| //           the corresponding HWM chunk can be backed up.
 | ||
| // dctnryStoreOids - Dictionary store OIDs that correspond to columns.
 | ||
| // dbRootHWMInfoVecCol - vector of last local HWM info for each DBRoot
 | ||
| //     (asssigned to current PM) for each column in tblOid.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::saveBulkRollbackMetaData(
 | ||
|     const std::vector<Column>& columns,
 | ||
|     const std::vector<OID>&    dctnryStoreOids,
 | ||
|     const std::vector<BRM::EmDbRootHWMInfo_v>& dbRootHWMInfoVecCol )
 | ||
| {
 | ||
|     int rc = NO_ERROR;
 | ||
|     bool bOpenedFile = false;
 | ||
| 
 | ||
|     try
 | ||
|     {
 | ||
|         std::vector<uint16_t> dbRoots;
 | ||
|         Config::getRootIdList( dbRoots );
 | ||
| 
 | ||
|         // Loop through DBRoot HWMs for this PM
 | ||
|         for (unsigned m = 0; m < dbRoots.size(); m++)
 | ||
|         {
 | ||
|             std::string metaFileName = openMetaFile( dbRoots[m] );
 | ||
|             bOpenedFile    = true;
 | ||
|             fCreatedSubDir = false;
 | ||
| 
 | ||
|             // Loop through the columns in the specified table
 | ||
|             for ( size_t i = 0; i < columns.size(); i++ )
 | ||
|             {
 | ||
|                 const BRM::EmDbRootHWMInfo_v& dbRootHWMInfo =
 | ||
|                     dbRootHWMInfoVecCol[i];
 | ||
| 
 | ||
|                 // Select dbRootHWMInfo that matches DBRoot for this iteration
 | ||
|                 unsigned k = 0;
 | ||
| 
 | ||
|                 for (; k < dbRootHWMInfo.size(); k++)
 | ||
|                 {
 | ||
|                     if (dbRoots[m] == dbRootHWMInfo[k].dbRoot)
 | ||
|                         break;
 | ||
|                 }
 | ||
| 
 | ||
|                 if (k >= dbRootHWMInfo.size()) // logic error; should not happen
 | ||
|                 {
 | ||
|                     std::ostringstream oss;
 | ||
|                     oss << "Error creating meta file; DBRoot" << dbRoots[m] <<
 | ||
|                         " listed in Calpont config file, but not in extentmap"
 | ||
|                         " for OID " << columns[i].dataFile.oid;
 | ||
|                     throw WeException( oss.str(), ERR_INVALID_PARAM );
 | ||
|                 }
 | ||
| 
 | ||
|                 uint16_t dbRoot    = dbRootHWMInfo[k].dbRoot;
 | ||
|                 uint32_t partition = 0;
 | ||
|                 uint16_t segment   = 0;
 | ||
|                 HWM       localHWM  = 0;
 | ||
|                 bool      bExtentWithData = false;
 | ||
| 
 | ||
|                 // For empty DBRoot (totalBlocks == 0),
 | ||
|                 // leave partition, segment, and HWM set to 0
 | ||
|                 if ((dbRootHWMInfo[k].totalBlocks > 0) ||
 | ||
|                         (dbRootHWMInfo[k].status == BRM::EXTENTOUTOFSERVICE))
 | ||
|                 {
 | ||
|                     partition = dbRootHWMInfo[k].partitionNum;
 | ||
|                     segment   = dbRootHWMInfo[k].segmentNum;
 | ||
|                     localHWM  = dbRootHWMInfo[k].localHWM;
 | ||
|                     bExtentWithData = true;
 | ||
|                 }
 | ||
| 
 | ||
|                 // Save column meta-data info to support bulk rollback
 | ||
|                 writeColumnMetaData(
 | ||
|                     metaFileName,
 | ||
|                     bExtentWithData,
 | ||
|                     columns[i].dataFile.oid,
 | ||
|                     dbRoot,
 | ||
|                     partition,
 | ||
|                     segment,
 | ||
|                     localHWM,
 | ||
|                     columns[i].colDataType,
 | ||
|                     ColDataTypeStr[ columns[i].colDataType ],
 | ||
|                     columns[i].colWidth,
 | ||
|                     columns[i].compressionType );
 | ||
| 
 | ||
|                 // Save dctnry store meta-data info to support bulk rollback
 | ||
|                 if ( dctnryStoreOids[i] > 0 )
 | ||
|                 {
 | ||
|                     std::vector<uint32_t> segList;
 | ||
|                     std::string segFileListErrMsg;
 | ||
| 
 | ||
|                     if (bExtentWithData)
 | ||
|                     {
 | ||
|                         std::string dirName;
 | ||
|                         FileOp fileOp(false);
 | ||
|                         rc = fileOp.getDirName( dctnryStoreOids[i],
 | ||
|                                                 dbRoot, partition, dirName );
 | ||
| 
 | ||
|                         if (rc != NO_ERROR)
 | ||
|                         {
 | ||
|                             WErrorCodes ec;
 | ||
|                             std::ostringstream oss;
 | ||
|                             oss << "Bulk rollback error constructing path "
 | ||
|                                 "for dictionary " << dctnryStoreOids[i] <<
 | ||
|                                 "; dbRoot-"    << dbRoot    <<
 | ||
|                                 "; partition-" << partition <<
 | ||
|                                 "; "           << ec.errorString(rc);
 | ||
| 
 | ||
|                             throw WeException( oss.str(), rc );
 | ||
|                         }
 | ||
| 
 | ||
|                         rc = BulkRollbackMgr::getSegFileList(dirName, false,
 | ||
|                                                              segList,
 | ||
|                                                              segFileListErrMsg);
 | ||
| 
 | ||
|                         if (rc != NO_ERROR)
 | ||
|                         {
 | ||
|                             WErrorCodes ec;
 | ||
|                             std::ostringstream oss;
 | ||
|                             oss << "Bulk rollback error for dictionary " <<
 | ||
|                                 dctnryStoreOids[i]        <<
 | ||
|                                 "; directory-" << dirName <<
 | ||
|                                 "; " << segFileListErrMsg <<
 | ||
|                                 "; " << ec.errorString(rc);
 | ||
| 
 | ||
|                             throw WeException( oss.str(), rc );
 | ||
|                         }
 | ||
|                     }   // end of "if (bExtentWithData)"
 | ||
| 
 | ||
|                     if (segList.size() == 0)
 | ||
|                     {
 | ||
|                         writeDictionaryStoreMetaNoDataMarker(
 | ||
|                             columns[i].dataFile.oid,
 | ||
|                             dctnryStoreOids[i],
 | ||
|                             dbRoot,
 | ||
|                             partition,
 | ||
|                             0, // segment
 | ||
|                             columns[i].compressionType );
 | ||
|                     }
 | ||
|                     else
 | ||
|                     {
 | ||
|                         // Loop thru dictionary store seg files for this DBRoot
 | ||
|                         for (unsigned int kk = 0; kk < segList.size(); kk++)
 | ||
|                         {
 | ||
|                             unsigned int segDictionary = segList[kk];
 | ||
| 
 | ||
|                             // check HWM for dictionary store file
 | ||
|                             HWM dictHWMStore;
 | ||
|                             int extState;
 | ||
|                             rc = BRMWrapper::getInstance()->getLocalHWM(
 | ||
|                                      dctnryStoreOids[i],
 | ||
|                                      partition,
 | ||
|                                      segDictionary,
 | ||
|                                      dictHWMStore,
 | ||
|                                      extState );
 | ||
| 
 | ||
|                             if (rc != NO_ERROR)
 | ||
|                             {
 | ||
|                                 WErrorCodes ec;
 | ||
|                                 std::ostringstream oss;
 | ||
|                                 oss << "Error getting rollback HWM for "
 | ||
|                                     "dictionary file " << dctnryStoreOids[i] <<
 | ||
|                                     "; partition-" << partition <<
 | ||
|                                     "; segment-"   << segDictionary <<
 | ||
|                                     "; " << ec.errorString(rc);
 | ||
|                                 throw WeException( oss.str(), rc );
 | ||
|                             }
 | ||
| 
 | ||
|                             writeDictionaryStoreMetaData(
 | ||
|                                 columns[i].dataFile.oid,
 | ||
|                                 dctnryStoreOids[i],
 | ||
|                                 dbRoot,
 | ||
|                                 partition,
 | ||
|                                 segDictionary,
 | ||
|                                 dictHWMStore,
 | ||
|                                 columns[i].compressionType );
 | ||
| 
 | ||
|                         } // loop thru dictionary store seg files in this DBRoot
 | ||
|                     }     // dictionary OID has 1 or more seg files in partition
 | ||
|                 }         // if dictionary column
 | ||
| 
 | ||
|                 // For a compressed column, backup the starting HWM chunk if the
 | ||
|                 // starting HWM block is not on an empty DBRoot (or outOfSrvc)
 | ||
|                 if ( (columns[i].compressionType) &&
 | ||
|                         (columns[i].dataFile.fDbRoot == dbRootHWMInfo[k].dbRoot) &&
 | ||
|                         (dbRootHWMInfo[k].totalBlocks > 0) &&
 | ||
|                         (dbRootHWMInfo[k].status != BRM::EXTENTOUTOFSERVICE) )
 | ||
|                 {
 | ||
|                     backupColumnHWMChunk(
 | ||
|                         columns[i].dataFile.oid,
 | ||
|                         columns[i].dataFile.fDbRoot,
 | ||
|                         columns[i].dataFile.fPartition,
 | ||
|                         columns[i].dataFile.fSegment,
 | ||
|                         columns[i].dataFile.hwm );
 | ||
|                 }
 | ||
| 
 | ||
|             }         // End of loop through columns
 | ||
| 
 | ||
|             // time to dump the string stream to file
 | ||
|             std::string data(fMetaDataStream.str());
 | ||
| 
 | ||
|             // this is to cover partical writes
 | ||
|             // no need for retry if low layer takes care partial writes.
 | ||
|             const char* p = data.c_str(); // buffer contents
 | ||
|             size_t      s = data.size();  // buffer size
 | ||
|             size_t      w = 0;            // total bytes written so far
 | ||
|             ssize_t     n = 0;            // bytes written in one write
 | ||
| 
 | ||
|             for (int i = 0; i < 10 && w < s; i++)
 | ||
|             {
 | ||
|                 n = fMetaDataFile->write(p + w, s - w);
 | ||
| 
 | ||
|                 if (n < 0)
 | ||
|                     break;
 | ||
| 
 | ||
|                 w += n;
 | ||
|             }
 | ||
| 
 | ||
|             if (w != s)
 | ||
|             {
 | ||
|                 int errRc = errno;
 | ||
|                 std::ostringstream oss;
 | ||
|                 oss << "Error writing bulk rollback meta-data file "
 | ||
|                     << metaFileName << "; written/expect:" << w << "/" << s
 | ||
|                     << "; err-" << errRc << "; " << strerror( errRc );
 | ||
|                 throw WeException(oss.str(), ERR_FILE_WRITE);
 | ||
|             }
 | ||
| 
 | ||
|             fMetaDataStream.str("");
 | ||
|             closeMetaFile( );
 | ||
|             bOpenedFile = false;
 | ||
| 
 | ||
|         }   // End of loop through DBRoot HWMs for this PM
 | ||
| 
 | ||
|         renameMetaFile( ); // rename meta files from temporary filenames
 | ||
|     }
 | ||
|     catch (WeException& ex) // catch exception to close file, then rethrow
 | ||
|     {
 | ||
|         if (bOpenedFile)
 | ||
|             closeMetaFile( );
 | ||
| 
 | ||
|         // If any error occurred, then go back and try to delete all meta files.
 | ||
|         // We catch and drop any exception, and return the original exception,
 | ||
|         // since we are already in error-mode at this point.
 | ||
|         try
 | ||
|         {
 | ||
|             deleteFile( );
 | ||
|         }
 | ||
|         catch (...)
 | ||
|         {
 | ||
|         }
 | ||
| 
 | ||
|         throw WeException( ex.what(), ex.errorCode() );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Open a meta data file to save info about the specified table OID.
 | ||
| //------------------------------------------------------------------------------
 | ||
| std::string RBMetaWriter::openMetaFile ( uint16_t dbRoot )
 | ||
| {
 | ||
|     std::string bulkRollbackPath( Config::getDBRootByNum( dbRoot ) );
 | ||
|     bulkRollbackPath += '/';
 | ||
|     bulkRollbackPath += DBROOT_BULK_ROLLBACK_SUBDIR;
 | ||
| 
 | ||
|     if ( !IDBPolicy::exists( bulkRollbackPath.c_str() ) )
 | ||
|     {
 | ||
|         if ( IDBPolicy::mkdir( bulkRollbackPath.c_str() ) != 0 )
 | ||
|         {
 | ||
|             std::ostringstream oss;
 | ||
|             oss << "Error creating bulk rollback directory " <<
 | ||
|                 bulkRollbackPath << ";" << std::endl;
 | ||
|             throw WeException( oss.str(), ERR_DIR_CREATE );
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     // Open the file
 | ||
|     std::ostringstream oss;
 | ||
|     oss << "/" << fTableOID;
 | ||
|     std::string metaFileName( bulkRollbackPath );
 | ||
|     metaFileName += oss.str();
 | ||
|     fMetaFileNames.insert( make_pair(dbRoot, metaFileName) );
 | ||
| 
 | ||
|     std::string tmpMetaFileName( metaFileName );
 | ||
|     tmpMetaFileName += TMP_FILE_SUFFIX;
 | ||
|     fMetaDataFile = IDBDataFile::open(IDBPolicy::getType(tmpMetaFileName.c_str(),
 | ||
|                                       IDBPolicy::WRITEENG),
 | ||
|                                       tmpMetaFileName.c_str(), "wb", 0);
 | ||
| 
 | ||
|     if ( !fMetaDataFile )
 | ||
|     {
 | ||
|         int errRc = errno;
 | ||
|         std::ostringstream oss;
 | ||
|         std::string eMsg;
 | ||
|         Convertor::mapErrnoToString(errRc, eMsg);
 | ||
|         oss << "Error opening bulk rollback file " <<
 | ||
|             tmpMetaFileName << "; " << eMsg;
 | ||
|         throw WeException( oss.str(), ERR_FILE_OPEN );
 | ||
|     }
 | ||
| 
 | ||
|     fMetaDataStream <<
 | ||
|                     "# VERSION: 4"             << std::endl <<
 | ||
|                     "# APPLICATION: " << fAppDesc << std::endl <<
 | ||
|                     "# PID:    " << ::getpid() << std::endl <<
 | ||
|                     "# TABLE:  " << fTableName << std::endl <<
 | ||
|                     "# COLUM1: coloid,"
 | ||
|                     "dbroot,part,seg,lastLocalHWM,type,typename,width,comp" <<
 | ||
|                     std::endl <<
 | ||
|                     "# COLUM2: coloid,"
 | ||
|                     "dbroot,part,seg,type,typename,width,comp" <<
 | ||
|                     std::endl <<
 | ||
|                     "# DSTOR1: coloid,dctoid,"
 | ||
|                     "dbroot,part,seg,localHWM,comp" << std::endl <<
 | ||
|                     "# DSTOR2: coloid,dctoid,"
 | ||
|                     "dbroot,part,seg,comp" << std::endl;
 | ||
| 
 | ||
|     // Clear out any data subdirectory
 | ||
|     // This is redundant because init() also calls deleteSubDir(), but it can't
 | ||
|     // hurt to call twice.  We "really" want to make sure we start with a clean
 | ||
|     // slate (no leftover backup chunk files from a previous import job).
 | ||
|     deleteSubDir( metaFileName );
 | ||
| 
 | ||
|     return metaFileName;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Close the currently open "temporary named" meta data file used during
 | ||
| // construction.  We will rename all the meta data files (for the various
 | ||
| // dbroots) to their eventual file names later, in renameMetaFile().
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::closeMetaFile ( )
 | ||
| {
 | ||
|     delete fMetaDataFile;
 | ||
|     fMetaDataFile = NULL;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Rename temporary metafile names to their permanent name, taking file names
 | ||
| // from fMetaFileNames.  In the normal case there will be one file name per
 | ||
| // DBRoot for the local PM we are running on.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::renameMetaFile ( )
 | ||
| {
 | ||
|     for (std::map<uint16_t, std::string>::const_iterator iter =
 | ||
|                 fMetaFileNames.begin(); iter != fMetaFileNames.end(); ++iter)
 | ||
|     {
 | ||
|         const std::string& metaFileName = iter->second;
 | ||
| 
 | ||
|         if (!metaFileName.empty())
 | ||
|         {
 | ||
|             std::string tmpMetaFileName = metaFileName;
 | ||
|             tmpMetaFileName += TMP_FILE_SUFFIX;
 | ||
| 
 | ||
|             if ( IDBPolicy::rename(tmpMetaFileName.c_str(), metaFileName.c_str()) )
 | ||
|             {
 | ||
|                 int errRc = errno;
 | ||
|                 std::ostringstream oss;
 | ||
|                 std::string eMsg;
 | ||
|                 Convertor::mapErrnoToString(errRc, eMsg);
 | ||
|                 oss << "Error renaming meta data file-" <<
 | ||
|                     tmpMetaFileName << "; will be deleted; " << eMsg;
 | ||
|                 throw WeException( oss.str(), ERR_METADATABKUP_FILE_RENAME );
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Delete the meta data files for the specified table OID.  We loop through all
 | ||
| // the DBRoots for the local PM, deleting the applicable meta data files.
 | ||
| // If the call to deleteSubDir() should throw an exception, we might not want
 | ||
| // to consider that a fatal error, but we go ahead and let the exception
 | ||
| // go up the call-stack so that the caller can log the corresponding message.
 | ||
| // The application code can then decide whether they want to consider this
 | ||
| // condition as fatal or not.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::deleteFile ( )
 | ||
| {
 | ||
|     for (std::map<uint16_t, std::string>::const_iterator iter =
 | ||
|                 fMetaFileNames.begin(); iter != fMetaFileNames.end(); ++iter)
 | ||
|     {
 | ||
|         const std::string& metaFileName = iter->second;
 | ||
| 
 | ||
|         if (!metaFileName.empty())
 | ||
|         {
 | ||
|             std::string tmpMetaFileName = metaFileName;
 | ||
|             tmpMetaFileName += TMP_FILE_SUFFIX;
 | ||
| 
 | ||
|             IDBPolicy::remove( metaFileName.c_str() );
 | ||
|             IDBPolicy::remove( tmpMetaFileName.c_str() );
 | ||
| 
 | ||
|             deleteSubDir( metaFileName ); // can throw an exception
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     fMetaFileNames.clear( );
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // New version of writeColumnMetaData for Shared-Nothing
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::writeColumnMetaData (
 | ||
|     const std::string& metaFileName,
 | ||
|     bool               withHWM,
 | ||
|     OID                columnOID,
 | ||
|     uint16_t           dbRoot,
 | ||
|     uint32_t           partition,
 | ||
|     uint16_t           segment,
 | ||
|     HWM                lastLocalHwm,
 | ||
|     CalpontSystemCatalog::ColDataType colType,
 | ||
|     const std::string& colTypeName,
 | ||
|     int                colWidth,
 | ||
|     int                compressionType )
 | ||
| {
 | ||
|     if (withHWM)
 | ||
|     {
 | ||
|         fMetaDataStream  << "COLUM1: " <<
 | ||
|                          columnOID    << ' ' <<
 | ||
|                          dbRoot       << ' ' <<
 | ||
|                          partition    << ' ' <<
 | ||
|                          segment      << ' ' <<
 | ||
|                          lastLocalHwm << ' ' <<
 | ||
|                          colType      << ' ' <<
 | ||
|                          colTypeName  << ' ' <<
 | ||
|                          colWidth;
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         fMetaDataStream  << "COLUM2: " <<
 | ||
|                          columnOID    << ' ' <<
 | ||
|                          dbRoot       << ' ' <<
 | ||
|                          partition    << ' ' <<
 | ||
|                          segment      << ' ' <<
 | ||
|                          colType      << ' ' <<
 | ||
|                          colTypeName  << ' ' <<
 | ||
|                          colWidth;
 | ||
|     }
 | ||
| 
 | ||
|     if (compressionType)
 | ||
|         fMetaDataStream << ' ' << compressionType << ' ';
 | ||
| 
 | ||
|     fMetaDataStream << std::endl;
 | ||
| 
 | ||
|     // If column is compressed, then create directory for storing HWM chunks
 | ||
|     if (compressionType)
 | ||
|     {
 | ||
|         if (!fCreatedSubDir)
 | ||
|         {
 | ||
|             // @bug 5572 - Don't need db backup files for HDFS;
 | ||
|             //             use hdfs buffer file
 | ||
|             if (!IDBPolicy::useHdfs())
 | ||
|                 createSubDir( metaFileName );
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // New version of writeDictionaryStoreMetaData for Shared-Nothing.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::writeDictionaryStoreMetaData (
 | ||
|     OID      columnOID,
 | ||
|     OID      dictionaryStoreOID,
 | ||
|     uint16_t dbRoot,
 | ||
|     uint32_t partition,
 | ||
|     uint16_t segment,
 | ||
|     HWM      localHwm,
 | ||
|     int      compressionType )
 | ||
| {
 | ||
|     fMetaDataStream        << "DSTOR1: " <<
 | ||
|                            columnOID          << ' ' <<
 | ||
|                            dictionaryStoreOID << ' ' <<
 | ||
|                            dbRoot             << ' ' <<
 | ||
|                            partition          << ' ' <<
 | ||
|                            segment            << ' ' <<
 | ||
|                            localHwm;
 | ||
| 
 | ||
|     if (compressionType)
 | ||
|         fMetaDataStream << ' ' << compressionType << ' ';
 | ||
| 
 | ||
|     fMetaDataStream << std::endl;
 | ||
| 
 | ||
|     // Save dictionary meta data for later use in backing up the HWM chunks
 | ||
|     if (compressionType)
 | ||
|     {
 | ||
|         RBChunkInfo chunkInfo(
 | ||
|             dictionaryStoreOID, dbRoot, partition, segment, localHwm);
 | ||
|         fRBChunkDctnrySet.insert( chunkInfo );
 | ||
| 
 | ||
|         if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
 | ||
|             printDctnryChunkList(chunkInfo, "after adding ");
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // New version of writeDictionaryStoreMetaNoDataMarker for Shared-Nothing.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::writeDictionaryStoreMetaNoDataMarker (
 | ||
|     OID      columnOID,
 | ||
|     OID      dictionaryStoreOID,
 | ||
|     uint16_t dbRoot,
 | ||
|     uint32_t partition,
 | ||
|     uint16_t segment,
 | ||
|     int      compressionType )
 | ||
| {
 | ||
|     fMetaDataStream        << "DSTOR2: " <<
 | ||
|                            columnOID          << ' ' <<
 | ||
|                            dictionaryStoreOID << ' ' <<
 | ||
|                            dbRoot             << ' ' <<
 | ||
|                            partition          << ' ' <<
 | ||
|                            segment;
 | ||
| 
 | ||
|     if (compressionType)
 | ||
|         fMetaDataStream << ' ' << compressionType << ' ';
 | ||
| 
 | ||
|     fMetaDataStream << std::endl;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Create the subdirectory we will use to backup data needed for rollback.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::createSubDir( const std::string& metaFileName )
 | ||
| {
 | ||
|     std::string bulkRollbackSubPath( metaFileName );
 | ||
|     bulkRollbackSubPath += DATA_DIR_SUFFIX;
 | ||
| 
 | ||
|     if ( IDBPolicy::mkdir( bulkRollbackSubPath.c_str() ) != 0 )
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error creating bulk rollback data subdirectory " <<
 | ||
|             bulkRollbackSubPath << ";";
 | ||
|         throw WeException( oss.str(), ERR_DIR_CREATE );
 | ||
|     }
 | ||
| 
 | ||
|     fCreatedSubDir = true;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Delete the subdirectory used to backup data needed for rollback.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::deleteSubDir( const std::string& metaFileName )
 | ||
| {
 | ||
|     std::string bulkRollbackSubPath( metaFileName );
 | ||
|     bulkRollbackSubPath += DATA_DIR_SUFFIX;
 | ||
| 
 | ||
|     if ( IDBPolicy::remove( bulkRollbackSubPath.c_str() ) != 0 )
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error deleting bulk rollback data subdirectory " <<
 | ||
|             bulkRollbackSubPath << ";";
 | ||
|         throw WeException( oss.str(), ERR_FILE_DELETE );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Backup the contents of the HWM chunk for the specified column OID extent,
 | ||
| // so that the chunk is available for bulk rollback.
 | ||
| // This operation is only performed for compressed columns.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::backupColumnHWMChunk(
 | ||
|     OID       columnOID,
 | ||
|     uint16_t  dbRoot,
 | ||
|     uint32_t  partition,
 | ||
|     uint16_t  segment,
 | ||
|     HWM       startingHWM)
 | ||
| {
 | ||
|     // @bug 5572 - Don't need db backup file for HDFS; we use hdfs buffer file
 | ||
|     if (!IDBPolicy::useHdfs())
 | ||
|     {
 | ||
|         backupHWMChunk( true,
 | ||
|                         columnOID, dbRoot, partition, segment, startingHWM );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Backup the contents of the HWM chunk for the specified dictionary store OID
 | ||
| // extent, so that the chunk is available for bulk rollback.
 | ||
| // This operation is only performed for compressed columns.  Once the chunk is
 | ||
| // saved, we remove that OID, partition, and segment from the internal list
 | ||
| // (fRBChunkDctnrySet) that is maintained.
 | ||
| // Return value indicates whether the specified file needs to be backed up or
 | ||
| // not.
 | ||
| //
 | ||
| // This function MUST be maintained to be thread-safe so that multiple threads
 | ||
| // can concurrently call this function, with each thread managing a different
 | ||
| // dictionary column.
 | ||
| //------------------------------------------------------------------------------
 | ||
| // @bug 5572 - HDFS usage: add return flag to indicate backup status
 | ||
| bool RBMetaWriter::backupDctnryHWMChunk(
 | ||
|     OID       dctnryOID,
 | ||
|     uint16_t  dbRoot,
 | ||
|     uint32_t  partition,
 | ||
|     uint16_t  segment)
 | ||
| {
 | ||
|     bool bBackupApplies = false;
 | ||
| 
 | ||
|     if (fRBChunkDctnrySet.size() > 0)
 | ||
|     {
 | ||
|         RBChunkInfo chunkInfo(
 | ||
|             dctnryOID, 0, partition, segment, 0);
 | ||
|         RBChunkInfo chunkInfoFound(0, 0, 0, 0, 0);
 | ||
|         bool bFound = false;
 | ||
| 
 | ||
|         {
 | ||
|             // Use scoped lock to perform "find"
 | ||
|             boost::mutex::scoped_lock lock( fRBChunkDctnryMutex );
 | ||
| 
 | ||
|             if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
 | ||
|                 printDctnryChunkList(chunkInfo, "when searching ");
 | ||
| 
 | ||
|             RBChunkSet::iterator iter = fRBChunkDctnrySet.find ( chunkInfo );
 | ||
| 
 | ||
|             if (iter != fRBChunkDctnrySet.end())
 | ||
|             {
 | ||
|                 bFound = true;
 | ||
|                 chunkInfoFound = *iter;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         if (bFound)
 | ||
|         {
 | ||
|             if (chunkInfoFound.fPartition == partition)
 | ||
|             {
 | ||
|                 // @bug 5572 - Don't need db backup file for HDFS;
 | ||
|                 //             we use hdfs buffer file.  Set backup flag
 | ||
|                 //             so application knows to use tmp buffer file.
 | ||
|                 bBackupApplies = true;
 | ||
| 
 | ||
|                 if (!IDBPolicy::useHdfs())
 | ||
|                 {
 | ||
|                     backupHWMChunk(false, dctnryOID,
 | ||
|                                    dbRoot, partition, segment, chunkInfoFound.fHwm);
 | ||
|                 }
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 // How could this happen?  Ended up asking for different
 | ||
|                 // partition than expected for the first instance of this
 | ||
|                 // OID and segment file.  Perhaps initial blockskipping
 | ||
|                 // or something caused us to advance to another segment file
 | ||
|                 // without ever changing the expected extent.  At any rate
 | ||
|                 // we still fall through and delete our entry because we
 | ||
|                 // apparently did not end up changing the chunk referenced
 | ||
|                 // by this RBChunkInfo object.
 | ||
|             }
 | ||
| 
 | ||
|             {
 | ||
|                 // Use scoped lock to perform "erase"
 | ||
|                 boost::mutex::scoped_lock lock( fRBChunkDctnryMutex );
 | ||
|                 fRBChunkDctnrySet.erase( chunkInfoFound );
 | ||
| 
 | ||
|                 if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
 | ||
|                     printDctnryChunkList(chunkInfoFound, "after deleting ");
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     return bBackupApplies;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Backup entire contents of HWM file for the specified columnOID,dbRoot,etc,
 | ||
| // so that the file is available for bulk rollback.  This function is used for
 | ||
| // HDFS files only.  This operation is only performed for compressed columns.
 | ||
| //
 | ||
| // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
 | ||
| // See that function description for more details.  This is the reason
 | ||
| // backupHWMChunk() has to have a local FileOp object.  We can't share/reuse
 | ||
| // a FileOp data member variable unless we want to employ a mutex.
 | ||
| //------------------------------------------------------------------------------
 | ||
| // @bug 5572 - Stopped using backupHWMFile().
 | ||
| // Don't need db backup file for HDFS; we use hdfs buffer file
 | ||
| void RBMetaWriter::backupHWMFile(
 | ||
|     bool      bColumnFile, // is this a column (vs dictionary) file
 | ||
|     OID       columnOID,   // OID of column or dictionary store
 | ||
|     uint16_t  dbRoot,      // DB Root for db segment file
 | ||
|     uint32_t  partition,   // partition for db segment file
 | ||
|     uint16_t  segment,     // segment for db segment file
 | ||
|     HWM       startingHWM) // starting HWM for db segment file
 | ||
| {
 | ||
|     std::string fileType("column");
 | ||
| 
 | ||
|     if (!bColumnFile)
 | ||
|         fileType = "dictionary";
 | ||
| 
 | ||
|     FileOp fileOp; // @bug 4960: to keep thread-safe, we use local FileOp
 | ||
| 
 | ||
|     // Construct file name for db file to be backed up
 | ||
|     char dbFileName[FILE_NAME_SIZE];
 | ||
|     int rc = fileOp.getFileName( columnOID, dbFileName,
 | ||
|                                  dbRoot, partition, segment );
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error creating backup "   << fileType <<
 | ||
|             " file for OID " << columnOID <<
 | ||
|             "; Can't construct file name for DBRoot"  << dbRoot <<
 | ||
|             "; partition-"   << partition <<
 | ||
|             "; segment-"     << segment;
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     // Construct file name for backup copy of db file
 | ||
|     std::ostringstream ossFile;
 | ||
|     ossFile << "/" << columnOID << ".p" << partition << ".s" << segment;
 | ||
|     std::string backupFileName;
 | ||
|     rc = getSubDirPath( dbRoot, backupFileName );
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error creating backup "   << fileType <<
 | ||
|             " file for OID " << columnOID <<
 | ||
|             "; Can't find matching meta file for DBRoot" << dbRoot;
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     backupFileName += ossFile.str();
 | ||
| 
 | ||
|     std::string backupFileNameTmp = backupFileName;
 | ||
|     backupFileNameTmp += TMP_FILE_SUFFIX;
 | ||
| 
 | ||
|     //if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
 | ||
|     if (fLog)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backing up HWM file for "      << fileType <<
 | ||
|             " file for OID " << columnOID      <<
 | ||
|             "; file-"     << backupFileNameTmp <<
 | ||
|             "; HWM-"      << startingHWM;
 | ||
|         fLog->logMsg( oss.str(), MSGLVL_INFO2 );
 | ||
|     }
 | ||
| 
 | ||
|     // Copy the db file to a temporary name
 | ||
|     IDBFileSystem& fs = IDBPolicy::getFs( backupFileNameTmp.c_str() );
 | ||
| 
 | ||
|     if ( !fs.exists(dbFileName) )
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error creating backup "   << fileType <<
 | ||
|             " file for OID " << columnOID <<
 | ||
|             "; dbfile does not exist for DBRoot" << dbRoot <<
 | ||
|             "; partition-"   << partition <<
 | ||
|             "; segment-"     << segment;
 | ||
|         throw WeException( oss.str(), ERR_FILE_NOT_EXIST );
 | ||
|     }
 | ||
| 
 | ||
|     rc = fs.copyFile( dbFileName, backupFileNameTmp.c_str() );
 | ||
| 
 | ||
|     if (rc != 0)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error copying backup for " << fileType <<
 | ||
|             " OID-"        << columnOID <<
 | ||
|             "; DBRoot-"    << dbRoot    <<
 | ||
|             "; partition-" << partition <<
 | ||
|             "; segment-"   << segment   <<
 | ||
|             "; rc-"        << rc;
 | ||
| 
 | ||
|         fs.remove( backupFileNameTmp.c_str() );
 | ||
|         throw WeException( oss.str(), ERR_METADATABKUP_COMP_WRITE_BULK_BKUP );
 | ||
|     }
 | ||
| 
 | ||
|     // Rename temporary named backup file to final name
 | ||
|     rc = fs.rename( backupFileNameTmp.c_str(), backupFileName.c_str() );
 | ||
| 
 | ||
|     if (rc != 0)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error renaming temp backup for " << fileType <<
 | ||
|             " OID-"        << columnOID <<
 | ||
|             "; DBRoot-"    << dbRoot    <<
 | ||
|             "; partition-" << partition <<
 | ||
|             "; segment-"   << segment   <<
 | ||
|             "; rc-"        << rc;
 | ||
| 
 | ||
|         fs.remove( backupFileNameTmp.c_str() );
 | ||
|         fs.remove( backupFileName.c_str() );
 | ||
|         throw WeException( oss.str(), ERR_METADATABKUP_COMP_RENAME );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Backup the contents of the HWM chunk for the specified columnOID,dbRoot,etc,
 | ||
| // so that the chunk is available for bulk rollback.  This function is used for
 | ||
| // non-hdfs files.  This operation is only performed for compressed columns.
 | ||
| //
 | ||
| // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
 | ||
| // See that function description for more details.  This is the reason
 | ||
| // backupHWMChunk() has to have a local FileOp object.  We can't share/reuse
 | ||
| // a FileOp data member variable unless we want to employ a mutex.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::backupHWMChunk(
 | ||
|     bool      bColumnFile, // is this a column (vs dictionary) file
 | ||
|     OID       columnOID,   // OID of column or dictionary store
 | ||
|     uint16_t  dbRoot,      // DB Root for db segment file
 | ||
|     uint32_t  partition,   // partition for db segment file
 | ||
|     uint16_t  segment,     // segment for db segment file
 | ||
|     HWM       startingHWM) // starting HWM for db segment file
 | ||
| {
 | ||
|     std::string fileType("column");
 | ||
| 
 | ||
|     if (!bColumnFile)
 | ||
|         fileType = "dictionary";
 | ||
| 
 | ||
|     // Open the applicable database column segment file
 | ||
|     std::string segFile;
 | ||
|     FileOp fileOp; // @bug 4960: to keep thread-safe, we use local FileOp
 | ||
|     IDBDataFile* dbFile = fileOp.openFile( columnOID,
 | ||
|                                            dbRoot,
 | ||
|                                            partition,
 | ||
|                                            segment,
 | ||
|                                            segFile,
 | ||
|                                            "rb" );
 | ||
| 
 | ||
|     if ( !dbFile )
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error opening " << fileType <<
 | ||
|             " file for OID-" << columnOID <<
 | ||
|             "; DBRoot-"      << dbRoot    <<
 | ||
|             "; partition-"   << partition <<
 | ||
|             "; segment-"     << segment;
 | ||
|         throw WeException( oss.str(), ERR_FILE_OPEN );
 | ||
|     }
 | ||
| 
 | ||
|     // Get the size of the file, so we know where to truncate back to.
 | ||
|     long long fileSizeBytes;
 | ||
|     int rc = fileOp.getFileSize( dbFile, fileSizeBytes);
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error getting file size for " << fileType <<
 | ||
|             " OID-"        << columnOID <<
 | ||
|             "; DBRoot-"    << dbRoot    <<
 | ||
|             "; partition-" << partition <<
 | ||
|             "; segment-"   << segment   <<
 | ||
|             "; " << ec.errorString(rc);
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     // Read Control header
 | ||
|     char controlHdr[ IDBCompressInterface::HDR_BUF_LEN ];
 | ||
|     rc = fileOp.readFile( dbFile, (unsigned char*)controlHdr,
 | ||
|                           IDBCompressInterface::HDR_BUF_LEN );
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error reading " << fileType <<
 | ||
|             " file control hdr for OID-" << columnOID <<
 | ||
|             "; DBRoot-"          << dbRoot    <<
 | ||
|             "; partition-"       << partition <<
 | ||
|             "; segment-"         << segment   <<
 | ||
|             "; " << ec.errorString(rc);
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     IDBCompressInterface compressor;
 | ||
|     int rc1 = compressor.verifyHdr( controlHdr );
 | ||
| 
 | ||
|     if (rc1 != 0)
 | ||
|     {
 | ||
|         rc = ERR_METADATABKUP_COMP_VERIFY_HDRS;
 | ||
| 
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error verifying " << fileType <<
 | ||
|             " file control hdr for OID-" << columnOID <<
 | ||
|             "; DBRoot-"          << dbRoot    <<
 | ||
|             "; partition-"       << partition <<
 | ||
|             "; segment-"         << segment   <<
 | ||
|             "; " << ec.errorString(rc)        <<
 | ||
|             "; rc: "             << rc1;
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     // Read Pointer header data
 | ||
|     uint64_t hdrSize    = compressor.getHdrSize(controlHdr);
 | ||
|     uint64_t ptrHdrSize = hdrSize - IDBCompressInterface::HDR_BUF_LEN;
 | ||
|     char* pointerHdr    = new char[ptrHdrSize];
 | ||
|     rc = fileOp.readFile( dbFile, (unsigned char*)pointerHdr, ptrHdrSize );
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error reading " << fileType <<
 | ||
|             " file pointer hdr for OID-" << columnOID <<
 | ||
|             "; DBRoot-"          << dbRoot    <<
 | ||
|             "; partition-"       << partition <<
 | ||
|             "; segment-"         << segment   <<
 | ||
|             "; " << ec.errorString(rc);
 | ||
|         delete[] pointerHdr;
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     CompChunkPtrList     chunkPtrs;
 | ||
|     rc = compressor.getPtrList(pointerHdr, ptrHdrSize, chunkPtrs );
 | ||
|     delete[] pointerHdr;
 | ||
| 
 | ||
|     if (rc != 0)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error getting " << fileType <<
 | ||
|             " file hdr for OID-" << columnOID <<
 | ||
|             "; DBRoot-"          << dbRoot    <<
 | ||
|             "; partition-"       << partition <<
 | ||
|             "; segment-"         << segment;
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), ERR_METADATABKUP_COMP_PARSE_HDRS );
 | ||
|     }
 | ||
| 
 | ||
|     // Locate HWM chunk
 | ||
|     unsigned int chunkIndex             = 0;
 | ||
|     unsigned int blockOffsetWithinChunk = 0;
 | ||
|     unsigned char* buffer               = 0;
 | ||
|     uint64_t chunkSize                  = 0;
 | ||
|     compressor.locateBlock(startingHWM, chunkIndex, blockOffsetWithinChunk);
 | ||
| 
 | ||
|     if (chunkIndex < chunkPtrs.size())
 | ||
|     {
 | ||
|         chunkSize = chunkPtrs[chunkIndex].second;
 | ||
| 
 | ||
|         // Read the HWM chunk
 | ||
|         rc = fileOp.setFileOffset(dbFile, chunkPtrs[chunkIndex].first, SEEK_SET);
 | ||
| 
 | ||
|         if (rc != NO_ERROR)
 | ||
|         {
 | ||
|             WErrorCodes ec;
 | ||
|             std::ostringstream oss;
 | ||
|             oss << "Backup error seeking in " << fileType <<
 | ||
|                 " file for OID-" << columnOID <<
 | ||
|                 "; DBRoot-"      << dbRoot    <<
 | ||
|                 "; partition-"   << partition <<
 | ||
|                 "; segment-"     << segment   <<
 | ||
|                 "; " << ec.errorString(rc);
 | ||
|             fileOp.closeFile( dbFile );
 | ||
|             throw WeException( oss.str(), rc );
 | ||
|         }
 | ||
| 
 | ||
|         buffer = new unsigned char[ chunkPtrs[chunkIndex].second ];
 | ||
|         rc = fileOp.readFile( dbFile, buffer, chunkPtrs[chunkIndex].second );
 | ||
| 
 | ||
|         if (rc != NO_ERROR)
 | ||
|         {
 | ||
|             WErrorCodes ec;
 | ||
|             std::ostringstream oss;
 | ||
|             oss << "Backup error reading in " << fileType <<
 | ||
|                 " file for OID-" << columnOID <<
 | ||
|                 "; DBRoot-"      << dbRoot    <<
 | ||
|                 "; partition-"   << partition <<
 | ||
|                 "; segment-"     << segment   <<
 | ||
|                 "; " << ec.errorString(rc);
 | ||
|             delete []buffer;
 | ||
|             fileOp.closeFile( dbFile );
 | ||
|             throw WeException( oss.str(), rc );
 | ||
|         }
 | ||
|     }
 | ||
|     else if (startingHWM == 0)
 | ||
|     {
 | ||
|         // Okay to proceed.  Empty file with no chunks.  Save 0 length chunk.
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|         rc = ERR_METADATABKUP_COMP_CHUNK_NOT_FOUND;
 | ||
| 
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error for " << fileType <<
 | ||
|             " file for OID-" << columnOID <<
 | ||
|             "; DBRoot-"      << dbRoot    <<
 | ||
|             "; partition-"   << partition <<
 | ||
|             "; segment-"     << segment   <<
 | ||
|             "; hwm-"         << startingHWM <<
 | ||
|             "; chunkIdx-"    << chunkIndex  <<
 | ||
|             "; numPtrs-"     << chunkPtrs.size() <<
 | ||
|             "; not in hdrPtrs"  <<
 | ||
|             "; " << ec.errorString(rc);
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     // Backup the HWM chunk
 | ||
|     std::string errMsg;
 | ||
|     rc = writeHWMChunk(bColumnFile, columnOID, dbRoot, partition, segment,
 | ||
|                        buffer, chunkSize, fileSizeBytes, startingHWM, errMsg);
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backup error writing backup for " << fileType <<
 | ||
|             " OID-"        << columnOID <<
 | ||
|             "; DBRoot-"    << dbRoot    <<
 | ||
|             "; partition-" << partition <<
 | ||
|             "; segment-"   << segment   <<
 | ||
|             "; "           << errMsg;
 | ||
|         delete []buffer;
 | ||
|         fileOp.closeFile( dbFile );
 | ||
|         throw WeException( oss.str(), rc );
 | ||
|     }
 | ||
| 
 | ||
|     // Close the applicable database column segment file and free memory
 | ||
|     delete []buffer;
 | ||
|     fileOp.closeFile( dbFile );
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Writes out the specified HWM chunk to disk, in case we need it for bulk
 | ||
| // rollback.  If an error occurs, errMsg will contain the error message.
 | ||
| // This function is careful not to create a corrupt file (should the system
 | ||
| // crash in the middle of writing the file for example).  It's imperative
 | ||
| // that during a failure of any kind, that we not "accidentally" create and
 | ||
| // leave around a corrupt or incomplete HWM backup file that could cause a
 | ||
| // bulk rollback to fail, and eventually corrupt a data base file.
 | ||
| // So this function first creates the HWM backup file to a temp file, and
 | ||
| // after it is successfully created, it is it renamed to the final destination.
 | ||
| // If anything goes wrong, we try to delete any files we were creating.
 | ||
| //
 | ||
| // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
 | ||
| // See that function description for more details.
 | ||
| //------------------------------------------------------------------------------
 | ||
| int RBMetaWriter::writeHWMChunk(
 | ||
|     bool                 bColumnFile, // is this a column (vs dictionary) file
 | ||
|     OID                  columnOID,   // OID of column or dictionary store
 | ||
|     uint16_t             dbRoot,      // dbroot for db segment file
 | ||
|     uint32_t             partition,   // partition for db segment file
 | ||
|     uint16_t             segment,     // segment for db segment file
 | ||
|     const unsigned char* compressedOutBuf, // compressed chunk to be written
 | ||
|     uint64_t             chunkSize,   // number of bytes in compressedOutBuf
 | ||
|     uint64_t             fileSize,    // size of file in bytes
 | ||
|     HWM                  chunkHWM,    // HWM in the chunk being written
 | ||
|     std::string&         errMsg) const// error msg if error occurs
 | ||
| {
 | ||
|     std::ostringstream ossFile;
 | ||
|     ossFile << "/" << columnOID << ".p" << partition << ".s" << segment;
 | ||
|     std::string fileName;
 | ||
|     int rc = getSubDirPath( dbRoot, fileName );
 | ||
| 
 | ||
|     if (rc != NO_ERROR)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Error creating backup file for OID " << columnOID <<
 | ||
|             "; Can't find matching meta file for DBRoot" << dbRoot;
 | ||
|         errMsg = oss.str();
 | ||
|         return ERR_METADATABKUP_COMP_OPEN_BULK_BKUP;
 | ||
|     }
 | ||
| 
 | ||
|     fileName += ossFile.str();
 | ||
| 
 | ||
|     std::string fileNameTmp = fileName;
 | ||
|     fileNameTmp += TMP_FILE_SUFFIX;
 | ||
| 
 | ||
|     //if ( (fLog) && (fLog->isDebug(DEBUG_1)) )
 | ||
|     if (fLog)
 | ||
|     {
 | ||
|         std::string fileType("column");
 | ||
| 
 | ||
|         if (!bColumnFile)
 | ||
|             fileType = "dictionary";
 | ||
| 
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Backing up HWM chunk for " << fileType <<
 | ||
|             " OID-"       << columnOID <<
 | ||
|             "; file-"     << fileNameTmp <<
 | ||
|             "; HWM-"      << chunkHWM    <<
 | ||
|             "; bytes-"    << chunkSize   <<
 | ||
|             "; fileSize-" << fileSize;
 | ||
|         fLog->logMsg( oss.str(), MSGLVL_INFO2 );
 | ||
|     }
 | ||
| 
 | ||
|     IDBDataFile*  backupFile = IDBDataFile::open(
 | ||
|                                    IDBPolicy::getType( fileNameTmp.c_str(), IDBPolicy::WRITEENG ),
 | ||
|                                    fileNameTmp.c_str(),
 | ||
|                                    "w+b",
 | ||
|                                    0 );
 | ||
| 
 | ||
|     if (!backupFile)
 | ||
|     {
 | ||
|         int errRc = errno;
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         std::string eMsg;
 | ||
|         Convertor::mapErrnoToString(errRc, eMsg);
 | ||
|         oss << ec.errorString(ERR_METADATABKUP_COMP_OPEN_BULK_BKUP) <<
 | ||
|             "; " << eMsg;
 | ||
|         errMsg = oss.str();
 | ||
|         return ERR_METADATABKUP_COMP_OPEN_BULK_BKUP;
 | ||
|     }
 | ||
| 
 | ||
|     IDBFileSystem& fs = IDBPolicy::getFs( fileNameTmp.c_str() );
 | ||
| 
 | ||
|     // Format of backup compressed chunk file:
 | ||
|     //   8 byte unsigned int carrying chunk size
 | ||
|     //   8 byte unsigned int carrying original file size
 | ||
|     //   N bytes containing compressed chunk
 | ||
|     uint64_t sizeHdr[2];
 | ||
|     sizeHdr[0] = chunkSize;
 | ||
|     sizeHdr[1] = fileSize;
 | ||
|     size_t itemsWritten = backupFile->write(sizeHdr, sizeof(uint64_t) * 2) / (sizeof(uint64_t) * 2);
 | ||
| 
 | ||
|     if (itemsWritten != 1)
 | ||
|     {
 | ||
|         int errRc = errno;
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         std::string eMsg;
 | ||
|         Convertor::mapErrnoToString(errRc, eMsg);
 | ||
|         oss << ec.errorString(ERR_METADATABKUP_COMP_WRITE_BULK_BKUP) <<
 | ||
|             "; " << eMsg;
 | ||
|         errMsg = oss.str();
 | ||
| 
 | ||
|         delete backupFile;
 | ||
|         fs.remove( fileNameTmp.c_str() );
 | ||
|         return ERR_METADATABKUP_COMP_WRITE_BULK_BKUP;
 | ||
|     }
 | ||
| 
 | ||
|     if (chunkSize > 0)
 | ||
|     {
 | ||
|         itemsWritten = backupFile->write(compressedOutBuf, chunkSize ) / chunkSize;
 | ||
| 
 | ||
|         if (itemsWritten != 1)
 | ||
|         {
 | ||
|             int errRc = errno;
 | ||
|             WErrorCodes ec;
 | ||
|             std::ostringstream oss;
 | ||
|             std::string eMsg;
 | ||
|             Convertor::mapErrnoToString(errRc, eMsg);
 | ||
|             oss << ec.errorString(ERR_METADATABKUP_COMP_WRITE_BULK_BKUP) <<
 | ||
|                 "; " << eMsg;
 | ||
|             errMsg = oss.str();
 | ||
| 
 | ||
|             delete backupFile;
 | ||
|             fs.remove( fileNameTmp.c_str() );
 | ||
|             return ERR_METADATABKUP_COMP_WRITE_BULK_BKUP;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     backupFile->flush();
 | ||
| //   IDBDataFile flush() does a sync where appropriate
 | ||
|     delete backupFile;
 | ||
| 
 | ||
| #ifdef _MSC_VER
 | ||
|     //Windows rename() behaves differently from Linux: it will return an error
 | ||
|     // if the target exists
 | ||
|     //FIXME: The Linux version seems a bit safer, perhaps implement a better
 | ||
|     // Windows port?
 | ||
|     unlink(fileName.c_str());
 | ||
| #endif
 | ||
| 
 | ||
|     // Rename HWM backup file to final name.
 | ||
|     if ( fs.rename(fileNameTmp.c_str(), fileName.c_str()) )
 | ||
|     {
 | ||
|         int errRc = errno;
 | ||
|         WErrorCodes ec;
 | ||
|         std::ostringstream oss;
 | ||
|         std::string eMsg;
 | ||
|         Convertor::mapErrnoToString(errRc, eMsg);
 | ||
|         oss << ec.errorString(ERR_METADATABKUP_COMP_RENAME) << "; " << eMsg;
 | ||
|         errMsg = oss.str();
 | ||
| 
 | ||
|         fs.remove( fileNameTmp.c_str() );
 | ||
|         fs.remove( fileName.c_str() );
 | ||
|         return ERR_METADATABKUP_COMP_RENAME;
 | ||
|     }
 | ||
| 
 | ||
|     return NO_ERROR;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Returns the directory path to be used for storing any backup data files.
 | ||
| //
 | ||
| // This function MUST be kept thread-safe in support of backupDctnryHWMChunk().
 | ||
| // See that function description for more details.
 | ||
| //------------------------------------------------------------------------------
 | ||
| int RBMetaWriter::getSubDirPath( uint16_t dbRoot,
 | ||
|                                  std::string& bulkRollbackSubPath ) const
 | ||
| {
 | ||
|     std::map<uint16_t, std::string>::const_iterator iter =
 | ||
|         fMetaFileNames.find( dbRoot );
 | ||
| 
 | ||
|     if (iter == fMetaFileNames.end())
 | ||
|     {
 | ||
|         return ERR_INVALID_PARAM;
 | ||
|     }
 | ||
| 
 | ||
|     bulkRollbackSubPath  = iter->second;
 | ||
|     bulkRollbackSubPath += DATA_DIR_SUFFIX;
 | ||
| 
 | ||
|     return NO_ERROR;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Prints list of compressed dictionary HWM chunks that we are tracking,
 | ||
| // in order to backup to disk as needed, before we start adding rows to a
 | ||
| // previously existing chunk.
 | ||
| //------------------------------------------------------------------------------
 | ||
| void RBMetaWriter::printDctnryChunkList(
 | ||
|     const RBChunkInfo& rbChk,
 | ||
|     const char* assocAction)
 | ||
| {
 | ||
|     if (fLog)
 | ||
|     {
 | ||
|         std::ostringstream oss;
 | ||
|         oss << "Dumping metaDictHWMChunks " << assocAction <<
 | ||
|             rbChk << ":";
 | ||
| 
 | ||
|         if (fRBChunkDctnrySet.size() > 0)
 | ||
|         {
 | ||
|             RBChunkSet::iterator iter = fRBChunkDctnrySet.begin();
 | ||
|             int k = 1;
 | ||
| 
 | ||
|             while (iter != fRBChunkDctnrySet.end())
 | ||
|             {
 | ||
|                 oss << std::endl;
 | ||
|                 oss << '\t' << k << ". " << *iter;
 | ||
| 
 | ||
|                 ++k;
 | ||
|                 ++iter;
 | ||
|             }
 | ||
|         }
 | ||
|         else
 | ||
|         {
 | ||
|             oss << std::endl;
 | ||
|             oss << '\t' << "Empty list";
 | ||
|         }
 | ||
| 
 | ||
|         fLog->logMsg( oss.str(), MSGLVL_INFO2 );
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Verify that specified string represents Version 3 file format
 | ||
| //------------------------------------------------------------------------------
 | ||
| /* static */
 | ||
| bool RBMetaWriter::verifyVersion3(const char* versionRec)
 | ||
| {
 | ||
|     if (strncmp(versionRec, VERSION3_REC, VERSION3_REC_LEN) == 0)
 | ||
|         return true;
 | ||
|     else
 | ||
|         return false;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Verify that specified string represents Version 4 file format
 | ||
| //------------------------------------------------------------------------------
 | ||
| /* static */
 | ||
| bool RBMetaWriter::verifyVersion4(const char* versionRec)
 | ||
| {
 | ||
|     if (strncmp(versionRec, VERSION4_REC, VERSION4_REC_LEN) == 0)
 | ||
|         return true;
 | ||
|     else
 | ||
|         return false;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Verify that specified record type is a Column1 record
 | ||
| //------------------------------------------------------------------------------
 | ||
| /* static */
 | ||
| bool RBMetaWriter::verifyColumn1Rec(const char* recType)
 | ||
| {
 | ||
|     if (strncmp(recType, COLUMN1_REC, COLUMN1_REC_LEN) == 0)
 | ||
|         return true;
 | ||
|     else
 | ||
|         return false;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Verify that specified record type is a Column2 record
 | ||
| //------------------------------------------------------------------------------
 | ||
| /* static */
 | ||
| bool RBMetaWriter::verifyColumn2Rec(const char* recType)
 | ||
| {
 | ||
|     if (strncmp(recType, COLUMN2_REC, COLUMN2_REC_LEN) == 0)
 | ||
|         return true;
 | ||
|     else
 | ||
|         return false;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Verify that specified record type is a DStore1 record
 | ||
| //------------------------------------------------------------------------------
 | ||
| /* static */
 | ||
| bool RBMetaWriter::verifyDStore1Rec(const char* recType)
 | ||
| {
 | ||
|     if (strncmp(recType, DSTORE1_REC, DSTORE1_REC_LEN) == 0)
 | ||
|         return true;
 | ||
|     else
 | ||
|         return false;
 | ||
| }
 | ||
| 
 | ||
| //------------------------------------------------------------------------------
 | ||
| // Verify that specified record type is a DStore2 record
 | ||
| //------------------------------------------------------------------------------
 | ||
| /* static */
 | ||
| bool RBMetaWriter::verifyDStore2Rec(const char* recType)
 | ||
| {
 | ||
|     if (strncmp(recType, DSTORE2_REC, DSTORE2_REC_LEN) == 0)
 | ||
|         return true;
 | ||
|     else
 | ||
|         return false;
 | ||
| }
 | ||
| 
 | ||
| } // end of namespace
 |