You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1414 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1414 lines
		
	
	
		
			52 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
 |