/* 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_colop.cpp 4740 2013-08-15 22:26:46Z chao $ /** @file */ #include #include #include #include #include using namespace std; #include "we_colop.h" #include "we_log.h" #include "we_dbfileop.h" #include "we_dctnrycompress.h" #include "we_colopcompress.h" #include "idbcompress.h" #include "writeengine.h" #include "cacheutils.h" using namespace execplan; #include "IDBDataFile.h" #include "IDBPolicy.h" using namespace idbdatafile; namespace WriteEngine { struct RefcolInfo { int localHwm; unsigned numExtents; }; /** * Constructor */ ColumnOp::ColumnOp() { //memset(m_workBlock.data, 0, BYTE_PER_BLOCK); } ColumnOp::ColumnOp(Log* logger) { setDebugLevel(logger->getDebugLevel()); setLogger (logger); } /** * Default Destructor */ ColumnOp::~ColumnOp() {} /*********************************************************** * DESCRIPTION: * Allocate Row ID * PARAMETERS: * tableFid - the file id for table bitmap file * totalRow - the total number of rows need to be allocated * useStartingExtent - Indicates whether rows can be added to an existing * starting extent * RETURN: * NO_ERROR if success * rowIdArray - allocation of the row id left here ***********************************************************/ int ColumnOp::allocRowId(const TxnID& txnid, bool useStartingExtent, Column& column, uint64_t totalRow, RID* rowIdArray, HWM& hwm, bool& newExtent, uint64_t& rowsLeft, HWM& newHwm, bool& newFile, ColStructList& newColStructList, DctnryStructList& newDctnryStructList, std::vector > & dbRootExtentTrackers, bool insertSelect, bool isBatchInsert, OID tableOid, bool isFirstBatchPm) { //MultiFiles per OID: always append the rows to the end for now. // See if the current HWM block might be in an abbreviated extent that // needs to be expanded, if we end up adding enough rows. bool bCheckAbbrevExtent = false; uint64_t numBlksPerInitialExtent = INITIAL_EXTENT_ROWS_TO_DISK/BYTE_PER_BLOCK * column.colWidth; int counter = 0; uint64_t totalRowPerBlock = BYTE_PER_BLOCK/column.colWidth; uint64_t extentRows = BRMWrapper::getInstance()->getExtentRows(); if (useStartingExtent) { // DMC-SHARED_NOTHING_NOTE: Is it safe to assume only part0 seg0 is abbreviated? if ((column.dataFile.fPartition == 0) && (column.dataFile.fSegment == 0) && ((hwm+1) <= numBlksPerInitialExtent)) bCheckAbbrevExtent = abbreviatedExtent(column.dataFile.pFile, column.colWidth); //The current existed rows upto hwm uint64_t currentRows = totalRowPerBlock * hwm; uint64_t numExtentsFilled = currentRows / extentRows; uint64_t rowsAvailable = extentRows - (numExtentsFilled * extentRows); rowsLeft = totalRow < rowsAvailable ? 0 : totalRow - rowsAvailable; } else { rowsLeft = totalRow; } newExtent = false; uint32_t j = 0, i=0, rowsallocated = 0; int rc = 0; newFile = false; Column newCol; unsigned char buf[BYTE_PER_BLOCK]; if (useStartingExtent) { // ZZ. For insert select, skip the hwm block and start inserting from the next block // to avoid self insert issue. //For batch insert: if not first batch, use the saved last rid to start adding rows. if (!insertSelect || !isFirstBatchPm) { //..Search the HWM block for empty rows rc = readBlock(column.dataFile.pFile, buf, hwm); if ( rc != NO_ERROR) return rc; for(j = 0; j < totalRowPerBlock; j++) { if (isEmptyRow(buf, j, column)) { rowIdArray[counter] = getRowId(hwm, column.colWidth, j); rowsallocated++; counter++; if (rowsallocated >= totalRow) break; } } } } if (rowsallocated < totalRow) { if (useStartingExtent) { //..Search remaining blks in current extent (after HWM) for empty rows //Need go to next block //need check whether this block is the last block for this extent while (((totalRowPerBlock * (hwm+1)) % extentRows) > 0) { hwm++; // Expand abbreviated initial extent on disk if needed. if (bCheckAbbrevExtent) { if ((hwm+1) > numBlksPerInitialExtent) { RETURN_ON_ERROR(expandAbbrevExtent(column)); bCheckAbbrevExtent = false; } } RETURN_ON_ERROR(readBlock(column.dataFile.pFile, buf, hwm)); for(j = 0; j < totalRowPerBlock; j++) { if (isEmptyRow(buf, j, column)) { rowIdArray[counter] = getRowId(hwm, column.colWidth, j); rowsallocated++; counter++; if (rowsallocated >= totalRow) break; } } if (rowsallocated >= totalRow) break; } } if ((rowsallocated == 0) && isFirstBatchPm) { TableMetaData::removeTableMetaData(tableOid); //TableMetaData* tableMetaData= TableMetaData::makeTableMetaData(tableOid); } //Check if a new extent is needed if (rowsallocated < totalRow) { //Create another extent uint16_t dbRoot; uint32_t partition = 0; uint16_t segment; IDBDataFile* pFile = NULL; std::string segFile; rowsLeft = 0; int allocSize = 0; newExtent = true; if ((column.dataFile.fid < 3000) || (!isBatchInsert)) //systables or single insert { dbRoot = column.dataFile.fDbRoot; } else { //Find out where the rest rows go BRM::LBID_t startLbid; //need to put in a loop until newExtent is true newExtent = dbRootExtentTrackers[column.colNo]->nextSegFile(dbRoot, partition, segment, newHwm, startLbid); TableMetaData* tableMetaData= TableMetaData::makeTableMetaData(tableOid); while (!newExtent) { /*partially filled extent encountered due to user moved dbroot. Set hwm to the end of the extent. If compressed,fill the rest eith empty values. */ unsigned int BLKS_PER_EXTENT = 0; unsigned int nBlks = 0; unsigned int nRem = 0; FileOp fileOp; long long fileSizeBytes = 0; for (i=0; i < dbRootExtentTrackers.size(); i++) { if (i != column.colNo) dbRootExtentTrackers[i]->nextSegFile(dbRoot, partition, segment, newHwm, startLbid); // Round up HWM to the end of the current extent BLKS_PER_EXTENT =(BRMWrapper::getInstance()->getExtentRows() * newColStructList[i].colWidth)/BYTE_PER_BLOCK; nBlks = newHwm + 1; nRem = nBlks % BLKS_PER_EXTENT; if (nRem > 0) newHwm = nBlks - nRem + BLKS_PER_EXTENT - 1; else newHwm = nBlks - 1; //save it to set in the end ColExtsInfo aColExtsInfo = tableMetaData->getColExtsInfo(newColStructList[i].dataOid); ColExtInfo aExt; aExt.dbRoot =dbRoot; aExt.partNum = partition; aExt.segNum = segment; aExt.hwm = newHwm; aExt.isNewExt = false; aExt.current = false; aColExtsInfo.push_back(aExt); if (newColStructList[i].fCompressionType > 0) { uint64_t emptyVal = getEmptyRowValue(newColStructList[i].colDataType, newColStructList[i].colWidth); string errorInfo; rc = fileOp.fillCompColumnExtentEmptyChunks(newColStructList[i].dataOid, newColStructList[i].colWidth, emptyVal, dbRoot, partition, segment, newHwm, segFile, errorInfo); if (rc != NO_ERROR) return rc; } //@Bug 4758. Check whether this is a abbreviated extent else if (newColStructList[i].fCompressionType == 0) { rc = fileOp.getFileSize(newColStructList[i].dataOid, dbRoot, partition, segment, fileSizeBytes); if (rc != NO_ERROR) return rc; if (fileSizeBytes == (long long) INITIAL_EXTENT_ROWS_TO_DISK * newColStructList[i].colWidth) { IDBDataFile* pFile = fileOp.openFile( newColStructList[i].dataOid, dbRoot, partition, segment, segFile ); if ( !pFile ) { rc = ERR_FILE_OPEN; return rc; } uint64_t emptyVal = getEmptyRowValue(newColStructList[i].colDataType, newColStructList[i].colWidth); rc = fileOp.expandAbbrevColumnExtent( pFile, dbRoot, emptyVal, newColStructList[i].colWidth); //set hwm for this extent. fileOp.closeFile(pFile); if (rc != NO_ERROR) return rc; } } tableMetaData->setColExtsInfo(newColStructList[i].dataOid, aColExtsInfo); } newExtent = dbRootExtentTrackers[column.colNo]->nextSegFile(dbRoot, partition, segment, newHwm, startLbid); } } std::vector extents; if (newExtent) { //extend all columns together std::vector cols; BRM::CreateStripeColumnExtentsArgIn createStripeColumnExtentsArgIn; for (i=0; i < newColStructList.size(); i++) { createStripeColumnExtentsArgIn.oid = newColStructList[i].dataOid; createStripeColumnExtentsArgIn.width = newColStructList[i].colWidth; createStripeColumnExtentsArgIn.colDataType = newColStructList[i].colDataType; cols.push_back(createStripeColumnExtentsArgIn); } rc = BRMWrapper::getInstance()->allocateStripeColExtents(cols, dbRoot, partition, segment, extents); newHwm = extents[column.colNo].startBlkOffset; if (rc != NO_ERROR) return rc; //Create column files vector lbids; vector colDataTypes; //BRM::CPInfoList_t cpinfoList; //BRM::CPInfo cpInfo; //cpInfo.max = numeric_limits::min(); //cpInfo.min = numeric_limits::max(); //cpInfo.seqNum = -1; for ( i=0; i < extents.size(); i++) { setColParam(newCol, 0, newColStructList[i].colWidth, newColStructList[i].colDataType, newColStructList[i].colType, newColStructList[i].dataOid, newColStructList[i].fCompressionType, dbRoot, partition, segment); compressionType(newColStructList[i].fCompressionType); rc = extendColumn(newCol, false, extents[i].startBlkOffset, extents[i].startLbid, extents[i].allocSize, dbRoot, partition, segment, segFile, pFile, newFile); if (rc != NO_ERROR) return rc; //cpInfo.firstLbid = extents[i].startLbid; //cpinfoList.push_back(cpInfo); newColStructList[i].fColPartition = partition; newColStructList[i].fColSegment = segment; newColStructList[i].fColDbRoot = dbRoot; newDctnryStructList[i].fColPartition = partition; newDctnryStructList[i].fColSegment = segment; newDctnryStructList[i].fColDbRoot = dbRoot; lbids.push_back(extents[i].startLbid); colDataTypes.push_back(newColStructList[i].colDataType); } //mark the extents to updating //rc = BRMWrapper::getInstance()->setExtentsMaxMin(cpinfoList); rc = BRMWrapper::getInstance()->markExtentsInvalid(lbids, colDataTypes); if (rc != NO_ERROR) return rc; //create corresponding dictionary files if (newFile ) { boost::scoped_ptr we (new WriteEngineWrapper()); we->setTransId(txnid); we->setBulkFlag(true); std::map columnOids; for (i=0; i < newDctnryStructList.size(); i++) { if (newDctnryStructList[i].dctnryOid > 0) { rc = we->createDctnry(txnid, newDctnryStructList[i].dctnryOid, newDctnryStructList[i].colWidth, dbRoot, partition, segment, newDctnryStructList[i].fCompressionType); if ( rc != NO_ERROR) return rc; columnOids[newDctnryStructList[i].dctnryOid] = newDctnryStructList[i].dctnryOid ; } } we->flushDataFiles(rc, txnid, columnOids ); } } //save the extent info for batch insert if (isBatchInsert && newExtent) { TableMetaData* tableMetaData= TableMetaData::makeTableMetaData(tableOid); for (i=0; i < newColStructList.size(); i++) { ColExtsInfo aColExtsInfo = tableMetaData->getColExtsInfo(newColStructList[i].dataOid); ColExtsInfo::iterator it = aColExtsInfo.begin(); while (it != aColExtsInfo.end()) { if ((it->dbRoot == newColStructList[i].fColDbRoot) && (it->partNum == newColStructList[i].fColPartition) && (it->segNum == newColStructList[i].fColSegment)) break; it++; } ColExtInfo aExt; aExt.dbRoot = newColStructList[i].fColDbRoot; aExt.partNum = newColStructList[i].fColPartition; aExt.segNum = newColStructList[i].fColSegment; aExt.hwm = extents[i].startBlkOffset; aExt.isNewExt = true; aExt.current = true; aExt.isDict = false; aColExtsInfo.push_back(aExt); tableMetaData->setColExtsInfo(newColStructList[i].dataOid, aColExtsInfo); } for (i=0; i < newDctnryStructList.size(); i++) { if (newDctnryStructList[i].dctnryOid > 0) { ColExtsInfo aColExtsInfo = tableMetaData->getColExtsInfo(newDctnryStructList[i].dctnryOid); ColExtsInfo::iterator it = aColExtsInfo.begin(); while (it != aColExtsInfo.end()) { if ((it->dbRoot == newDctnryStructList[i].fColDbRoot) && (it->partNum == newDctnryStructList[i].fColPartition) && (it->segNum == newDctnryStructList[i].fColSegment)) break; it++; } if (it == aColExtsInfo.end()) //add this one to the list { ColExtInfo aExt; aExt.dbRoot = newDctnryStructList[i].fColDbRoot; aExt.partNum = newDctnryStructList[i].fColPartition; aExt.segNum = newDctnryStructList[i].fColSegment; aExt.compType = newDctnryStructList[i].fCompressionType; aExt.isDict = true; aColExtsInfo.push_back(aExt); } tableMetaData->setColExtsInfo(newDctnryStructList[i].dctnryOid, aColExtsInfo); } } } setColParam(newCol, 0, column.colWidth,column.colDataType, column.colType, column.dataFile.fid, column.compressionType, dbRoot, partition, segment); rc = openColumnFile(newCol, segFile, false); // @bug 5572 HDFS tmp file if (rc != NO_ERROR) return rc; //@Bug 3164 update compressed extent updateColumnExtent(newCol.dataFile.pFile, allocSize); //..Search first block of new extent for empty rows rc = readBlock(newCol.dataFile.pFile, buf, newHwm); if ( rc != NO_ERROR) return rc; for(j = 0; j < totalRowPerBlock; j++) { if (isEmptyRow(buf, j, column)) { rowIdArray[counter] = getRowId(newHwm, column.colWidth, j); rowsallocated++; rowsLeft++; counter++; if (rowsallocated >= totalRow) { break; } } } if (rowsallocated < totalRow) { //..Search remaining blks in new extent for empty rows newHwm++; while (((totalRowPerBlock * newHwm) % extentRows) > 0) { rc = readBlock(newCol.dataFile.pFile, buf, newHwm); if ( rc != NO_ERROR) return rc; for(j = 0; j < totalRowPerBlock; j++) { if (isEmptyRow(buf, j, column)) { rowIdArray[counter] = getRowId(newHwm, column.colWidth, j); rowsallocated++; rowsLeft++; counter++; if (rowsallocated >= totalRow) { break; } } } if ((rowsallocated < totalRow)) { newHwm++; } else break; } } } } if (rowsallocated < totalRow) { return 1; } if (!newExtent) rowsLeft = 0; return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Clear a column * PARAMETERS: * column - column * RETURN: * none ***********************************************************/ void ColumnOp::clearColumn(Column& column) const { if (column.dataFile.pFile) { column.dataFile.pFile->flush(); } //setColParam(column); closeColumnFile(column); setColParam(column); } /*********************************************************** * DESCRIPTION: * Close column's file * PARAMETERS: * column - column * RETURN: * none ***********************************************************/ void ColumnOp::closeColumnFile(Column& column) const { if (column.dataFile.pFile != NULL) closeFile(column.dataFile.pFile); column.dataFile.pFile = NULL; } /*********************************************************** * DESCRIPTION: * Create a column and its' related files * PARAMETERS: * column - column * colNo - column number * colWidth - column width * colType - column type * dataFid - the file id for column data file * dbRoot - DBRoot where file is to be located * partition-Starting partition number for segment file path * RETURN: * NO_ERROR if success * ERR_FILE_EXIST if file exists * ERR_FILE_CREATE if something wrong in creating the file ***********************************************************/ int ColumnOp::createColumn(Column& column, int colNo, int colWidth, CalpontSystemCatalog::ColDataType colDataType, ColType colType, FID dataFid, uint16_t dbRoot, uint32_t partition) { int rc, newWidth, allocSize; uint64_t emptyVal = 0; int compressionType = column.compressionType; setColParam(column, colNo, colWidth, colDataType, colType); emptyVal = getEmptyRowValue(colDataType, colWidth); newWidth = getCorrectRowWidth(colDataType, colWidth); column.dataFile.fid = dataFid; column.dataFile.fDbRoot = dbRoot; column.dataFile.fPartition = partition; column.dataFile.fSegment = 0; column.compressionType = compressionType; rc = createFile(column.dataFile.fid, allocSize, dbRoot, partition, colDataType, emptyVal, newWidth); if (rc != NO_ERROR) return rc; return NO_ERROR; } /* BUG931 * @brief Fills up a column with null/default values in all non-empty rows as the reference column. The reference column * would typically be another column of the same table. * * @param * * @return */ int ColumnOp::fillColumn(const TxnID& txnid, Column& column, Column& refCol, void * defaultVal, Dctnry* dctnry, ColumnOp* refColOp,const OID dictOid, const int dictColWidth, const string defaultValStr, bool autoincrement) { unsigned char refColBuf[BYTE_PER_BLOCK]; //Refernce column buffer unsigned char colBuf[BYTE_PER_BLOCK]; bool dirty = false; HWM colHwm = 0; RID maxRowId = 0; int size = sizeof(Token); uint64_t emptyVal; uint64_t refEmptyVal; long long startColFbo = 0; long long startRefColFbo = 0; int refBufOffset = 0; int colBufOffset = 0; uint64_t nexValNeeded = 0; uint64_t nextVal; uint32_t partition; uint16_t segment; HWM lastRefHwm; int rc = 0; std::string segFile, errorMsg; BRM::LBID_t startLbid; bool newFile = true; int allocSize = 0; /* boost::scoped_ptr dctnry; if (m_compressionType == 0) dctnry.reset(new DctnryCompress0); else dctnry.reset(new DctnryCompress1); boost::scoped_ptr refColOp; if (refCol.compressionType != 0) refColOp.reset(new ColumnOpCompress1); else refColOp.reset(new ColumnOpCompress0); */ //get dbroots from config Config config; config.initConfigCache(); std::vector rootList; config.getRootIdList( rootList ); emptyVal = getEmptyRowValue(column.colDataType, column.colWidth); refEmptyVal = getEmptyRowValue(refCol.colDataType, refCol.colWidth); //find the dbroots which have rows for refrence column unsigned int i=0, k=0; for (i=0; i < rootList.size(); i++) { std::vector refEntries; rc = BRMWrapper::getInstance()->getExtents_dbroot(refCol.dataFile.fid, refEntries, rootList[i]); std::vector::const_iterator iter = refEntries.begin(); while ( iter != refEntries.end() ) { //fill in for the new column for each extent in the reference column //organize the extents into a file std::vector fileExtents; fileExtents.push_back(refEntries[0]); //cout << "Get extent for ref oid:dbroot:part:seg = " << refCol.dataFile.fid<<":"< lastRefHwm) lastRefHwm = fileExtents[k].HWM; } //create extents for the new column // If we are processing the first extent in the first segment // file, we check to see if we have enough rows (256K) to re- // quire just create the initial abbrev extent for the new column. std::vector newEntries; if (( refEntries.size() == 1) && (refEntries[0].partitionNum == 0) && (refEntries[0].segmentNum == 0)) { //@Bug3565 use ref colwidth to calculate. unsigned int numBlksForFirstExtent = (INITIAL_EXTENT_ROWS_TO_DISK/BYTE_PER_BLOCK) * refCol.colWidth; if ((lastRefHwm+1) < numBlksForFirstExtent) { rc = createColumn(column, 0, column.colWidth, column.colDataType, WriteEngine::WR_CHAR, column.dataFile.fid, rootList[i], 0); if (rc != NO_ERROR) return rc; //cout << "createColumn for oid " << column.dataFile.fid << endl; BRM::EMEntry aEntry; aEntry.partitionNum = partition = 0; aEntry.segmentNum = segment = 0; aEntry.dbRoot = rootList[i]; newEntries.push_back(aEntry); if (dictOid >3000) //Create dictionary file if needed { rc = dctnry->createDctnry(dictOid, dictColWidth, rootList[i], partition, segment, startLbid, newFile); if (rc != NO_ERROR) return rc; //@Bug 5652. std::map oids1; oids1[dictOid] = dictOid; dctnry->flushFile(rc, oids1); dctnry->closeDctnry(); //tokenize default value if needed if (defaultValStr.length() > 0) { DctnryStruct dctnryStruct; dctnryStruct.dctnryOid = dictOid; dctnryStruct.columnOid = column.dataFile.fid; dctnryStruct.fColPartition = partition; dctnryStruct.fColSegment = segment; dctnryStruct.fColDbRoot = rootList[i]; dctnryStruct.colWidth = dictColWidth; dctnryStruct.fCompressionType = column.compressionType; DctnryTuple dctnryTuple; dctnryTuple.sigValue = (unsigned char*)defaultValStr.c_str(); dctnryTuple.sigSize = defaultValStr.length(); rc = dctnry->openDctnry(dctnryStruct.dctnryOid, dctnryStruct.fColDbRoot, dctnryStruct.fColPartition, dctnryStruct.fColSegment, false); // @bug 5572 HDFS tmp file rc = dctnry->updateDctnry(dctnryTuple.sigValue, dctnryTuple.sigSize, dctnryTuple.token); if (dctnryStruct.fCompressionType > 0) dctnry->closeDctnry(false); else dctnry->closeDctnry(true); if (rc != NO_ERROR) return rc; memcpy(defaultVal, &dctnryTuple.token, size); //@Bug 5652. std::map oids1; oids1[dictOid] = dictOid; dctnry->flushFile(rc, oids1); } } } } if (newEntries.size() == 0) { for (k = 0; k < fileExtents.size(); k++) { uint16_t dbroot = rootList[i]; partition = fileExtents[k].partitionNum; segment = fileExtents[k].segmentNum; if ( k == 0) { rc = addExtent(column, dbroot, partition, segment, segFile, startLbid, newFile, allocSize) ; if (rc != NO_ERROR) return rc; //Clean up will be done throgh DDLProc //cout << "extendColumn for oid " << column.dataFile.fid << endl; BRM::EMEntry aEntry; aEntry.partitionNum = partition; aEntry.segmentNum = segment; aEntry.dbRoot = rootList[i]; newEntries.push_back(aEntry); if ((dictOid >3000) && newFile) //Create dictionary file if needed { rc = dctnry->createDctnry(dictOid, dictColWidth, rootList[i], partition, segment, startLbid, newFile); if (rc != NO_ERROR) return rc; //@Bug 5652. std::map oids1; oids1[dictOid] = dictOid; dctnry->flushFile(rc, oids1); dctnry->closeDctnry(); //tokenize default value if needed if (defaultValStr.length() > 0) { DctnryStruct dctnryStruct; dctnryStruct.dctnryOid = dictOid; dctnryStruct.columnOid = column.dataFile.fid; dctnryStruct.fColPartition = partition; dctnryStruct.fColSegment = segment; dctnryStruct.fColDbRoot = rootList[i]; dctnryStruct.colWidth = dictColWidth; dctnryStruct.fCompressionType = column.compressionType; DctnryTuple dctnryTuple; dctnryTuple.sigValue = (unsigned char*)defaultValStr.c_str(); //WriteEngineWrapper wrapper; dctnryTuple.sigSize = defaultValStr.length(); //rc = wrapper.tokenize(txnid, dctnryStruct, dctnryTuple); rc = dctnry->openDctnry(dctnryStruct.dctnryOid, dctnryStruct.fColDbRoot, dctnryStruct.fColPartition, dctnryStruct.fColSegment, false); // @bug 5572 HDFS tmp file rc = dctnry->updateDctnry(dctnryTuple.sigValue, dctnryTuple.sigSize, dctnryTuple.token); if (dctnryStruct.fCompressionType > 0) dctnry->closeDctnry(false); else dctnry->closeDctnry(true); if (rc != NO_ERROR) return rc; memcpy(defaultVal, &dctnryTuple.token, size); //@Bug 5652. std::map oids1; oids1[dictOid] = dictOid; dctnry->flushFile(rc, oids1); } } } else //just add a extent to the file { rc = addExtent(column, dbroot, partition, segment, segFile, startLbid, newFile, allocSize) ; if (rc != NO_ERROR) return rc; //Clean up will be done throgh DDLProc } } } //Fill the new file with values //Open new column file and reference column file column.dataFile.fDbRoot = rootList[i]; column.dataFile.fPartition = newEntries[0].partitionNum; column.dataFile.fSegment = newEntries[0].segmentNum; RETURN_ON_ERROR(openColumnFile(column, segFile, false)); // @bug 5572 HDFS tmp file //cout << "Processing new col file " << segFile << endl; refCol.dataFile.fDbRoot = rootList[i]; refCol.dataFile.fPartition = newEntries[0].partitionNum; refCol.dataFile.fSegment = newEntries[0].segmentNum; std::string segFileRef; RETURN_ON_ERROR(refColOp->openColumnFile(refCol, segFileRef, false)); // @bug 5572 HDFS tmp file //cout << "Processing ref file " << segFileRef << " and hwm is " << lastRefHwm << endl; RETURN_ON_ERROR(refColOp->readBlock(refCol.dataFile.pFile, refColBuf, lastRefHwm)); refBufOffset = BYTE_PER_BLOCK - refCol.colWidth; maxRowId = (lastRefHwm * BYTE_PER_BLOCK)/refCol.colWidth; //Local maxRowId while(refBufOffset > 0) { if (memcmp(&refColBuf[refBufOffset], &refEmptyVal, refCol.colWidth) != 0) { maxRowId = maxRowId + (refBufOffset/refCol.colWidth); break; } refBufOffset -= refCol.colWidth; } //Compute local hwm for the new column colHwm = (maxRowId * column.colWidth) / BYTE_PER_BLOCK; //cout << " new col hwm is " << colHwm << endl; startRefColFbo = 0; startColFbo = 0; //Initizliaing to BYTE_PER_BLOCK to force read the first time refBufOffset = BYTE_PER_BLOCK; colBufOffset = BYTE_PER_BLOCK; dirty = false; BRM::CPInfo cpInfo; if (autoincrement) { uint64_t nextValStart = 0; while(startRefColFbo <= lastRefHwm || startColFbo <= colHwm) { //nexValNeeded = 0; //cout << "current startRefColFbo:startColFbo:refBufOffset:colBufOffset = " << startRefColFbo <<":"<< startColFbo <<":"< BYTE_PER_BLOCK) { //If current reference column block is fully processed get to the next one //cout << "reading from ref " << endl; RETURN_ON_ERROR(refColOp->readBlock(refCol.dataFile.pFile, refColBuf, startRefColFbo)); startRefColFbo++; refBufOffset = 0; nexValNeeded = 0; } if ((colBufOffset + column.colWidth) > BYTE_PER_BLOCK) { //Current block of the new colum is full. Write it if dirty and then get the next block if (dirty) { //cout << " writing to new col " << endl; RETURN_ON_ERROR(saveBlock(column.dataFile.pFile, colBuf, startColFbo-1)); dirty = false; } //cout << "reading from new col " << endl; RETURN_ON_ERROR(readBlock(column.dataFile.pFile, colBuf, startColFbo)); startColFbo++; colBufOffset = 0; } if (nexValNeeded == 0) { int tmpBufOffset = 0; while((tmpBufOffset + refCol.colWidth) <= BYTE_PER_BLOCK) { if (memcmp(refColBuf + tmpBufOffset, &refEmptyVal, refCol.colWidth) != 0) //Find the number of nextVal needed. { nexValNeeded++; //memcpy(colBuf + colBufOffset, defaultVal, column.colWidth); //dirty = true; } tmpBufOffset += refCol.colWidth; } //reserve the next value, should have a AI sequence in controller from DDLProc if (nexValNeeded > 0) { rc = BRMWrapper::getInstance()->getAutoIncrementRange(column.dataFile.fid, nexValNeeded, nextVal, errorMsg); if (rc != NO_ERROR) return rc; } nextValStart = nextVal; } //write the values to column //colBufOffset = 0; @Bug 5436 ref column coud have different column width while(((refBufOffset + refCol.colWidth) <= BYTE_PER_BLOCK) && ((colBufOffset + column.colWidth) <= BYTE_PER_BLOCK)) { if (memcmp(refColBuf + refBufOffset, &refEmptyVal, refCol.colWidth) != 0) //Find the number of nextVal needed. { memcpy(defaultVal, &nextVal, 8); nextVal++; memcpy(colBuf + colBufOffset, defaultVal, column.colWidth); dirty = true; } refBufOffset += refCol.colWidth; colBufOffset += column.colWidth; } } cpInfo.max = nextValStart + nexValNeeded -1; cpInfo.min = nextValStart; cpInfo.seqNum = 0; } else { while(startRefColFbo <= lastRefHwm || startColFbo <= colHwm) { if ((refBufOffset + refCol.colWidth) > BYTE_PER_BLOCK) { //If current reference column block is fully processed get to the next one RETURN_ON_ERROR(refColOp->readBlock(refCol.dataFile.pFile, refColBuf, startRefColFbo)); startRefColFbo++; refBufOffset = 0; } if ((colBufOffset + column.colWidth) > BYTE_PER_BLOCK) { //Current block of the new colum is full. Write it if dirty and then get the next block if (dirty) { RETURN_ON_ERROR(saveBlock(column.dataFile.pFile, colBuf, startColFbo-1)); dirty = false; } RETURN_ON_ERROR(readBlock(column.dataFile.pFile, colBuf, startColFbo)); startColFbo++; colBufOffset = 0; } while(((refBufOffset + refCol.colWidth) <= BYTE_PER_BLOCK) && ((colBufOffset + column.colWidth) <= BYTE_PER_BLOCK)) { if (memcmp(refColBuf + refBufOffset, &refEmptyVal, refCol.colWidth) != 0) { /*if (autoincrement) { memcpy(defaultVal, &nextVal, 8); nextVal++; } */ memcpy(colBuf + colBufOffset, defaultVal, column.colWidth); dirty = true; } else if (column.compressionType !=0) //@Bug 3866, fill the empty row value for compressed chunk { memcpy(colBuf + colBufOffset, &emptyVal, column.colWidth); dirty = true; } refBufOffset += refCol.colWidth; colBufOffset += column.colWidth; } } if (isUnsigned(column.colDataType)) { cpInfo.max = 0; cpInfo.min = static_cast(numeric_limits::max()); } else { cpInfo.max = numeric_limits::min(); cpInfo.min = numeric_limits::max(); } cpInfo.seqNum = -1; } if (dirty) { RETURN_ON_ERROR(saveBlock(column.dataFile.pFile, colBuf, startColFbo - 1)); dirty = false; } std::map oids; oids[column.dataFile.fid] = column.dataFile.fid; oids[refCol.dataFile.fid] = refCol.dataFile.fid; rc = flushFile(rc, oids); closeColumnFile(column); refColOp->closeColumnFile(refCol); oids.clear(); //Mark extents invalid first BRM::LBID_t startLbid; rc = BRMWrapper::getInstance()->getStartLbid(column.dataFile.fid, column.dataFile.fPartition, column.dataFile.fSegment, colHwm, startLbid); if (autoincrement) //@Bug 4074. Mark it invalid first to set later { BRM::CPInfo cpInfo1; if (isUnsigned(column.colDataType)) { cpInfo1.max = 0; cpInfo1.min = static_cast(numeric_limits::max()); } else { cpInfo1.max = numeric_limits::min(); cpInfo1.min = numeric_limits::max(); } cpInfo1.seqNum = -1; cpInfo1.firstLbid = startLbid; BRM::CPInfoList_t cpinfoList1; cpinfoList1.push_back(cpInfo1); rc = BRMWrapper::getInstance()->setExtentsMaxMin(cpinfoList1); if ( rc != NO_ERROR) return rc; } BRM::CPInfoList_t cpinfoList; cpInfo.firstLbid = startLbid; cpinfoList.push_back(cpInfo); //cout << "calling setExtentsMaxMin for startLbid = " << startLbid << endl; rc = BRMWrapper::getInstance()->setExtentsMaxMin(cpinfoList); if ( rc != NO_ERROR) return rc; //cout << "calling setLocalHWM for oid:hwm = " << column.dataFile.fid <<":"<setLocalHWM((OID)column.dataFile.fid,column.dataFile.fPartition, column.dataFile.fSegment,colHwm); if ( rc != NO_ERROR) return rc; //erase the entries from this dbroot. std::vector refEntriesTrimed; for (uint32_t m=0; m& dataFids) { return deleteFiles(dataFids); } int ColumnOp::dropPartitions(const std::vector& dataFids, const std::vector& partitions) { return deletePartitions(dataFids, partitions); } int ColumnOp::deleteOIDsFromExtentMap(const std::vector& dataFids) { int rc = 0; rc = BRMWrapper::getInstance()->deleteOIDsFromExtentMap(dataFids); return rc; } /************************************************************** * DESCRIPTION: * Add an extent to the specified column OID and DBRoot. * Partition and segment number (and HWM) of the segment file containing * the new extent are returned. * PARAMETERS: * column - input column attributes like OID and column width. * leaveFileOpen - indicates whether db file is to be left open upon return * hwm - The HWM (or fbo) of the column segment file where the * new extent begins. * startLbid - The starting LBID for the new extent. * allocSize - Number of blocks in new extent. * dbRoot - The DBRoot of the file with the new extent. * partition - The partition num of the file with the new extent. * segment - The segment number of the file with the new extent. * segFile - Name of the segment file to which the extent is added. * pFile - FILE ptr to the file where the extent is added. * newFile - Indicates if extent is added to new or existing file. * hdrs - Contents of headers if file is compressed. * RETURN: * NO_ERROR if success * other number if fail **************************************************************/ int ColumnOp::extendColumn( const Column& column, bool leaveFileOpen, HWM hwm, BRM::LBID_t startLbid, int allocSize, uint16_t dbRoot, uint32_t partition, uint16_t segment, std::string& segFile, IDBDataFile*& pFile, bool& newFile, char* hdrs) { uint64_t emptyVal = 0; emptyVal = getEmptyRowValue(column.colDataType, column.colWidth); int rc = extendFile(column.dataFile.fid, emptyVal, column.colWidth, hwm, startLbid, allocSize, dbRoot, partition, segment, segFile, pFile, newFile, hdrs); if (rc != NO_ERROR) { if ((!leaveFileOpen) && (pFile)) closeFile( pFile ); return rc; } // Only close file for DML/DDL; leave file open for bulkload if (!leaveFileOpen) closeFile( pFile ); return rc; } int ColumnOp::addExtent( const Column& column, uint16_t dbRoot, uint32_t partition, uint16_t segment, std::string& segFile, BRM::LBID_t& startLbid, bool& newFile, int& allocSize, char* hdrs) { uint64_t emptyVal = 0; emptyVal = getEmptyRowValue(column.colDataType, column.colWidth); int rc = addExtentExactFile(column.dataFile.fid, emptyVal, column.colWidth, allocSize, dbRoot, partition, segment, column.colDataType, segFile, startLbid, newFile, hdrs); return rc; } /*********************************************************** * DESCRIPTION: * Expand the current abbreviated extent in the column file to a full * extent. * PARAMETERS: * column - input column attributes like OID and column width. * RETURN: * NO_ERROR if success * other number if fail ***********************************************************/ int ColumnOp::expandAbbrevExtent(const Column& column) { uint64_t emptyVal = getEmptyRowValue(column.colDataType, column.colWidth); int rc = expandAbbrevColumnExtent(column.dataFile.pFile, column.dataFile.fDbRoot, emptyVal, column.colWidth); return rc; } /*********************************************************** * DESCRIPTION: * Get column data type * PARAMETERS: * name - type name * RETURN: * true if success, false otherwise ***********************************************************/ bool ColumnOp::getColDataType(const char* name, CalpontSystemCatalog::ColDataType& colDataType) const { bool bFound = false; for(int i = 0; i < CalpontSystemCatalog::NUM_OF_COL_DATA_TYPE; i++) if (strcmp(name, ColDataTypeStr[i]) == 0) { colDataType = static_cast(i); bFound = true; break; } return bFound; } /*********************************************************** * DESCRIPTION: * Initialize a column * PARAMETERS: * column - current column * RETURN: * none ***********************************************************/ void ColumnOp::initColumn(Column& column) const { setColParam(column); column.dataFile.pFile = NULL; } /*********************************************************** * DESCRIPTION: * Check whether the row is empty * PARAMETERS: * buf - data buffer * offset - buffer offset * column - current column * RETURN: * true if success, false otherwise ***********************************************************/ bool ColumnOp::isEmptyRow(unsigned char* buf, int offset, const Column& column) { bool emptyFlag = true; uint64_t curVal, emptyVal; memcpy(&curVal, buf + offset*column.colWidth, column.colWidth); emptyVal = getEmptyRowValue(column.colDataType, column.colWidth); if (/*curVal != emptyVal*/memcmp(&curVal, &emptyVal, column.colWidth)) emptyFlag = false; return emptyFlag; } /*********************************************************** * DESCRIPTION: * Check whether column parameters are valid * PARAMETERS: * column - current column * RETURN: * true if success, false otherwise ***********************************************************/ bool ColumnOp::isValid(Column& column) const { return /*column.colNo > 0 && */ column.colWidth > 0 ; } /*********************************************************** * DESCRIPTION: * Open all column related files * PARAMETERS: * column - column (includes the file id for column data file, * as well as the DBRoot, partition, and segment number) * segFile- is set to the name of the column segment file * that is opened. * RETURN: * NO_ERROR if success * ERR_FILE_READ if something wrong in reading the file ***********************************************************/ // @bug 5572 - HDFS usage: add *.tmp file backup flag int ColumnOp::openColumnFile(Column& column, std::string& segFile, bool useTmpSuffix, int ioBuffSize) const { if (!isValid(column)) return ERR_INVALID_PARAM; // open column data file column.dataFile.pFile = openFile(column, column.dataFile.fDbRoot, column.dataFile.fPartition, column.dataFile.fSegment, column.dataFile.fSegFileName, useTmpSuffix, "r+b", ioBuffSize); segFile = column.dataFile.fSegFileName; if (column.dataFile.pFile == NULL) { ostringstream oss; oss << "oid: " << column.dataFile.fid << " with path " << segFile; logging::Message::Args args; logging::Message message(1); args.add("Error opening file "); args.add(oss.str()); args.add(""); args.add(""); message.format(args); logging::LoggingID lid(21); logging::MessageLog ml(lid); ml.logErrorMessage( message ); return ERR_FILE_OPEN; } // open column bitmap file /* column.bitmapFile.pFile = openFile(column.bitmapFile.fid); if (column.bitmapFile.pFile == NULL) { closeFile(column.dataFile.pFile ); // clear previous one column.dataFile.pFile = NULL; return ERR_FILE_OPEN; } */ return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Open all table related files * PARAMETERS: * table - table structure * RETURN: * NO_ERROR if success * ERR_FILE_READ if something wrong in reading the file ***********************************************************/ /* int ColumnOp::openTableFile() const { // open table bitmap file return NO_ERROR; } */ /*********************************************************** * DESCRIPTION: * Set column parameters * PARAMETERS: * column - current column * colNo - column no * colWidth - column width * RETURN: * none ***********************************************************/ void ColumnOp::setColParam(Column& column, int colNo, int colWidth, CalpontSystemCatalog::ColDataType colDataType, ColType colType, FID dataFid, int compressionType, uint16_t dbRoot, uint32_t partition, uint16_t segment) const { column.colNo = colNo; column.colWidth = colWidth; column.colType = colType; column.colDataType = colDataType; column.dataFile.fid = dataFid; column.dataFile.fDbRoot = dbRoot; column.dataFile.fPartition = partition; column.dataFile.fSegment = segment; column.compressionType = compressionType; } /*********************************************************** * DESCRIPTION: * Write row(s) * PARAMETERS: * curCol - column information * totalRow - the total number of rows need to be inserted * rowIdArray - the array of row id, for performance purpose, I am assuming the rowIdArray is sorted * valArray - the array of row values * oldValArray - the array of old value * RETURN: * NO_ERROR if success, other number otherwise ***********************************************************/ int ColumnOp::writeRow(Column& curCol, uint64_t totalRow, const RID* rowIdArray, const void* valArray, bool bDelete ) { uint64_t i = 0, curRowId; int dataFbo, dataBio, curDataFbo = -1; unsigned char dataBuf[BYTE_PER_BLOCK]; bool bExit = false, bDataDirty = false; void* pVal = 0; // void* pOldVal; char charTmpBuf[8]; uint64_t emptyVal; int rc = NO_ERROR; while(!bExit) { curRowId = rowIdArray[i]; calculateRowId(curRowId, BYTE_PER_BLOCK/curCol.colWidth, curCol.colWidth, dataFbo, dataBio); // load another data block if necessary if (curDataFbo != dataFbo) { if (bDataDirty) { rc = saveBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); if ( rc != NO_ERROR) return rc; bDataDirty = false; } curDataFbo = dataFbo; rc = readBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); if ( rc != NO_ERROR) return rc; bDataDirty = true; } // This is a awkward way to convert void* and get ith element, I just don't have a good solution for that // How about pVal = valArray + i*curCol.colWidth? switch (curCol.colType) { // case WriteEngine::WR_LONG : pVal = &((long *) valArray)[i]; break; case WriteEngine::WR_FLOAT : if (!bDelete) pVal = &((float *) valArray)[i]; //pOldVal = &((float *) oldValArray)[i]; break; case WriteEngine::WR_DOUBLE : if (!bDelete) pVal = &((double *) valArray)[i]; //pOldVal = &((double *) oldValArray)[i]; break; case WriteEngine::WR_VARBINARY : // treat same as char for now case WriteEngine::WR_BLOB : case WriteEngine::WR_TEXT : case WriteEngine::WR_CHAR : if (!bDelete) { memcpy(charTmpBuf, (char*)valArray + i*8, 8); pVal = charTmpBuf; } //pOldVal = (char*)oldValArray + i*8; break; // case WriteEngine::WR_BIT : pVal = &((bool *) valArray)[i]; break; case WriteEngine::WR_SHORT : if (!bDelete) pVal = &((short *) valArray)[i]; //pOldVal = &((short *) oldValArray)[i]; break; case WriteEngine::WR_BYTE : if (!bDelete) pVal = &((char *) valArray)[i]; //pOldVal = &((char *) oldValArray)[i]; break; case WriteEngine::WR_LONGLONG: if (!bDelete) pVal = &((long long *) valArray)[i]; //pOldVal = &((long long *) oldValArray)[i]; break; case WriteEngine::WR_TOKEN: if (!bDelete) pVal = &((Token *) valArray)[i]; //pOldVal = &((Token *) oldValArray)[i]; break; case WriteEngine::WR_INT : if (!bDelete) pVal = &((int *) valArray)[i]; //pOldVal = &((int *) oldValArray)[i]; break; case WriteEngine::WR_USHORT: if (!bDelete) pVal = &((uint16_t *) valArray)[i]; //pOldVal = &((uint16_t *) oldValArray)[i]; break; case WriteEngine::WR_UBYTE : if (!bDelete) pVal = &((uint8_t *) valArray)[i]; //pOldVal = &((uint8_t *) oldValArray)[i]; break; case WriteEngine::WR_UINT : if (!bDelete) pVal = &((uint32_t *) valArray)[i]; //pOldVal = &((uint8_t *) oldValArray)[i]; break; case WriteEngine::WR_ULONGLONG: if (!bDelete) pVal = &((uint64_t *) valArray)[i]; //pOldVal = &((uint64_t *) oldValArray)[i]; break; default : if (!bDelete) pVal = &((int *) valArray)[i]; //pOldVal = &((int *) oldValArray)[i]; break; } // This is the stuff to retrieve old value //memcpy(pOldVal, dataBuf + dataBio, curCol.colWidth); if (bDelete) { emptyVal = getEmptyRowValue(curCol.colDataType, curCol.colWidth); pVal = &emptyVal; } // This is the write stuff writeBufValue(dataBuf + dataBio, pVal, curCol.colWidth); i++; if (i >= totalRow) bExit = true; } // take care of the cleanup if (bDataDirty && curDataFbo >= 0) rc = saveBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); return rc; } /*********************************************************** * DESCRIPTION: * Write rows * PARAMETERS: * curCol - column information * totalRow - the total number of rows need to be inserted * ridList - the vector of row id * valArray - the array of one row value * oldValArray - the array of old value * RETURN: * NO_ERROR if success, other number otherwise ***********************************************************/ int ColumnOp::writeRows(Column& curCol, uint64_t totalRow, const RIDList& ridList, const void* valArray, const void* oldValArray, bool bDelete ) { uint64_t i = 0, curRowId; int dataFbo, dataBio, curDataFbo = -1; unsigned char dataBuf[BYTE_PER_BLOCK]; bool bExit = false, bDataDirty = false; void* pVal = 0; //void* pOldVal; char charTmpBuf[8]; uint64_t emptyVal; int rc = NO_ERROR; while(!bExit) { curRowId = ridList[i]; calculateRowId(curRowId, BYTE_PER_BLOCK/curCol.colWidth, curCol.colWidth, dataFbo, dataBio); // load another data block if necessary if (curDataFbo != dataFbo) { if (bDataDirty) { rc = saveBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); if ( rc != NO_ERROR) return rc; curCol.dataFile.pFile->flush(); bDataDirty = false; } curDataFbo = dataFbo; //@Bug 4849. need to check error code to prevent disk error rc = readBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); if ( rc != NO_ERROR) return rc; bDataDirty = true; } // This is a awkward way to convert void* and get ith element, I just don't have a good solution for that // How about pVal = valArray? You're always getting the 0'th element here anyways. switch (curCol.colType) { // case WriteEngine::WR_LONG : pVal = &((long *) valArray)[i]; break; case WriteEngine::WR_FLOAT : if (!bDelete) pVal = &((float *) valArray)[0]; //pOldVal = &((float *) oldValArray)[i]; break; case WriteEngine::WR_DOUBLE : if (!bDelete) pVal = &((double *) valArray)[0]; //pOldVal = &((double *) oldValArray)[i]; break; case WriteEngine::WR_VARBINARY : // treat same as char for now case WriteEngine::WR_BLOB : case WriteEngine::WR_TEXT : case WriteEngine::WR_CHAR : if (!bDelete) { memcpy(charTmpBuf, (char*)valArray, 8); pVal = charTmpBuf; } //pOldVal = (char*)oldValArray + i*8; break; // case WriteEngine::WR_BIT : pVal = &((bool *) valArray)[i]; break; case WriteEngine::WR_SHORT : if (!bDelete) pVal = &((short *) valArray)[0]; //pOldVal = &((short *) oldValArray)[i]; break; case WriteEngine::WR_BYTE : if (!bDelete) pVal = &((char *) valArray)[0]; //pOldVal = &((char *) oldValArray)[i]; break; case WriteEngine::WR_LONGLONG: if (!bDelete) pVal = &((long long *) valArray)[0]; //pOldVal = &((long long *) oldValArray)[i]; break; case WriteEngine::WR_TOKEN: if (!bDelete) pVal = &((Token *) valArray)[0]; //pOldVal = &((Token *) oldValArray)[i]; break; case WriteEngine::WR_INT : if (!bDelete) pVal = &((int *) valArray)[0]; //pOldVal = &((int *) oldValArray)[i]; break; case WriteEngine::WR_USHORT : if (!bDelete) pVal = &((uint16_t *) valArray)[0]; //pOldVal = &((uint16_t *) oldValArray)[i]; break; case WriteEngine::WR_UBYTE : if (!bDelete) pVal = &((uint8_t *) valArray)[0]; //pOldVal = &((uint8_t *) oldValArray)[i]; break; case WriteEngine::WR_ULONGLONG: if (!bDelete) pVal = &((uint64_t *) valArray)[0]; //pOldVal = &((uint64_t *) oldValArray)[i]; break; case WriteEngine::WR_UINT : if (!bDelete) pVal = &((uint32_t *) valArray)[0]; //pOldVal = &((uint32_t *) oldValArray)[i]; break; default : if (!bDelete) pVal = &((int *) valArray)[0]; //pOldVal = &((int *) oldValArray)[i]; break; } // This is the stuff to retrieve old value //memcpy(pOldVal, dataBuf + dataBio, curCol.colWidth); if (bDelete) { emptyVal = getEmptyRowValue(curCol.colDataType, curCol.colWidth); pVal = &emptyVal; } // This is the write stuff writeBufValue(dataBuf + dataBio, pVal, curCol.colWidth); i++; if (i >= totalRow) bExit = true; } // take care of the cleanup if (bDataDirty && curDataFbo >= 0) { //@Bug 4849. need to check error code to prevent disk error rc = saveBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); } curCol.dataFile.pFile->flush(); return rc; } /*********************************************************** * DESCRIPTION: * Write rows * PARAMETERS: * curCol - column information * totalRow - the total number of rows need to be inserted * ridList - the vector of row id * valArray - the array of one row value * oldValArray - the array of old value * RETURN: * NO_ERROR if success, other number otherwise ***********************************************************/ int ColumnOp::writeRowsValues(Column& curCol, uint64_t totalRow, const RIDList& ridList, const void* valArray ) { uint64_t i = 0, curRowId; int dataFbo, dataBio, curDataFbo = -1; unsigned char dataBuf[BYTE_PER_BLOCK]; bool bExit = false, bDataDirty = false; void* pVal = 0; //void* pOldVal; char charTmpBuf[8]; int rc = NO_ERROR; while(!bExit) { curRowId = ridList[i]; calculateRowId(curRowId, BYTE_PER_BLOCK/curCol.colWidth, curCol.colWidth, dataFbo, dataBio); // load another data block if necessary if (curDataFbo != dataFbo) { if (bDataDirty) { rc = saveBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); if ( rc != NO_ERROR) return rc; bDataDirty = false; } curDataFbo = dataFbo; rc = readBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); if ( rc != NO_ERROR) return rc; bDataDirty = true; } // This is a awkward way to convert void* and get ith element, I just don't have a good solution for that switch (curCol.colType) { case WriteEngine::WR_FLOAT : pVal = &((float *) valArray)[i]; break; case WriteEngine::WR_DOUBLE : pVal = &((double *) valArray)[i]; break; case WriteEngine::WR_VARBINARY : // treat same as char for now case WriteEngine::WR_BLOB : case WriteEngine::WR_TEXT : case WriteEngine::WR_CHAR : { memcpy(charTmpBuf, (char*)valArray+i*8, 8); pVal = charTmpBuf; } break; case WriteEngine::WR_SHORT : pVal = &((short *) valArray)[i]; break; case WriteEngine::WR_BYTE : pVal = &((char *) valArray)[i]; break; case WriteEngine::WR_LONGLONG: pVal = &((long long *) valArray)[i]; break; case WriteEngine::WR_TOKEN: pVal = &((Token *) valArray)[i]; break; case WriteEngine::WR_INT : pVal = &((int *) valArray)[i]; break; case WriteEngine::WR_USHORT : pVal = &((uint16_t *) valArray)[i]; break; case WriteEngine::WR_UBYTE : pVal = &((uint8_t *) valArray)[i]; break; case WriteEngine::WR_ULONGLONG: pVal = &((uint64_t *) valArray)[i]; break; case WriteEngine::WR_UINT : pVal = &((uint32_t *) valArray)[i]; break; default : pVal = &((int *) valArray)[i]; break; } // This is the write stuff writeBufValue(dataBuf + dataBio, pVal, curCol.colWidth); i++; if (i >= totalRow) bExit = true; } // take care of the cleanup if (bDataDirty && curDataFbo >= 0) { rc = saveBlock(curCol.dataFile.pFile, dataBuf, curDataFbo); } return rc; } } //end of namespace // vim:ts=4 sw=4: