/* 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: columncommand-jl.cpp 9655 2013-06-25 23:08:13Z xlou $ // C++ Implementation: columncommand // // Description: // // // Author: Patrick LeBlanc , (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #include #include #include using namespace std; #include "primitivestep.h" #include "tablecolumn.h" #include "bpp-jl.h" #include "columncommand-jl.h" #include "dbrm.h" using namespace messageqcpp; namespace joblist { ColumnCommandJL::ColumnCommandJL(const pColScanStep& scan, vector lastLBID, bool hasAuxCol_, const std::vector& extentsAux_, execplan::CalpontSystemCatalog::OID oidAux) : extentsAux(extentsAux_), hasAuxCol(hasAuxCol_), fOidAux(oidAux) { BRM::DBRM dbrm; isScan = true; /* grab necessary vars from scan */ traceFlags = scan.fTraceFlags; filterString = scan.fFilterString; filterCount = scan.fFilterCount; colType = scan.fColType; BOP = scan.fBOP; extents = scan.extents; OID = scan.fOid; colName = scan.fName; rpbShift = scan.rpbShift; fIsDict = scan.fIsDict; fLastLbid = lastLBID; // cout << "CCJL inherited lastlbids: "; // for (uint32_t i = 0; i < lastLBID.size(); i++) // cout << lastLBID[i] << " "; // cout << endl; // cout << "Init columncommand from scan with OID " << OID << endl; /* I think modmask isn't necessary for scans */ divShift = scan.divShift; modMask = (1 << divShift) - 1; // @Bug 2889. Drop partition enhancement. Read FilesPerColumnPartition and ExtentsPerSegmentFile for use // in RID calculation. fFilesPerColumnPartition = DEFAULT_FILES_PER_COLUMN_PARTITION; // MCOL-4685 remove the option to set more than 2 extents per file (ExtentsPreSegmentFile). fExtentsPerSegmentFile = DEFAULT_EXTENTS_PER_SEGMENT_FILE; config::Config* cf = config::Config::makeConfig(); string fpc = cf->getConfig("ExtentMap", "FilesPerColumnPartition"); if (fpc.length() != 0) fFilesPerColumnPartition = cf->uFromText(fpc); } ColumnCommandJL::ColumnCommandJL(const pColStep& step) { BRM::DBRM dbrm; isScan = false; hasAuxCol = false; /* grab necessary vars from step */ traceFlags = step.fTraceFlags; filterString = step.fFilterString; filterCount = step.fFilterCount; colType = step.fColType; BOP = step.fBOP; extents = step.extents; divShift = step.divShift; modMask = step.modMask; rpbShift = step.rpbShift; OID = step.fOid; colName = step.fName; fIsDict = step.fIsDict; ResourceManager* rm = ResourceManager::instance(); numDBRoots = rm->getDBRootCount(); // grab the last LBID for this column. It's a _minor_ optimization for the block loader. // dbrm.getLastLocalHWM((BRM::OID_t)OID, dbroot, partNum, segNum, lastHWM); // dbrm.lookupLocal((BRM::OID_t)OID, partNum, segNum, lastHWM, fLastLbid); /* fLastLbid.resize(numDBRoots); for (uint32_t i = 0; i < numDBRoots; i++) { dbrm.getLastLocalHWM2((BRM::OID_t)OID, i+1, partNum, segNum, lastHWM); dbrm.lookupLocal((BRM::OID_t)OID, partNum, segNum, lastHWM, fLastLbid[i]); } */ // cout << "Init columncommand from step with OID " << OID << " and width " << colType.colWidth << endl; // @Bug 2889. Drop partition enhancement. Read FilesPerColumnPartition and ExtentsPerSegmentFile for use // in RID calculation. fFilesPerColumnPartition = DEFAULT_FILES_PER_COLUMN_PARTITION; // MCOL-4685 remove the option to set more than 2 extents per file (ExtentsPreSegmentFile). fExtentsPerSegmentFile = DEFAULT_EXTENTS_PER_SEGMENT_FILE; config::Config* cf = config::Config::makeConfig(); string fpc = cf->getConfig("ExtentMap", "FilesPerColumnPartition"); if (fpc.length() != 0) fFilesPerColumnPartition = cf->uFromText(fpc); } ColumnCommandJL::ColumnCommandJL(const ColumnCommandJL& prevCmd, const DictStepJL& dictWithFilters) { BRM::DBRM dbrm; /* grab necessary vars from scan */ traceFlags = prevCmd.traceFlags; // we should call this constructor only when paired with dictionary // and in that case previous command should not have any filters and // should be "dict" (tokens) column command. idbassert(dictWithFilters.getFilterCount() == 0 || prevCmd.filterCount == 0); idbassert(prevCmd.fIsDict); // need to reencode filters. filterString = dictWithFilters.reencodedFilterString(); // we have a limitation here. // consider this: textcol IS NULL AND textcol IN ('a', 'b') // XXX: should check. if (filterString.length() > 0 && (BOP = dictWithFilters.getBop() || prevCmd.filterString.length() < 1)) { filterCount = dictWithFilters.getFilterCount(); BOP = dictWithFilters.getBop(); fContainsRanges = true; } else { filterCount = prevCmd.filterCount; filterString = prevCmd.filterString; BOP = prevCmd.BOP; } isScan = prevCmd.isScan; hasAuxCol = prevCmd.hasAuxCol; extentsAux = prevCmd.extentsAux; colType = prevCmd.colType; extents = prevCmd.extents; OID = prevCmd.OID; colName = prevCmd.colName; rpbShift = prevCmd.rpbShift; fIsDict = prevCmd.fIsDict; fLastLbid = prevCmd.fLastLbid; lbid = prevCmd.lbid; traceFlags = prevCmd.traceFlags; dbroot = prevCmd.dbroot; numDBRoots = prevCmd.numDBRoots; /* I think modmask isn't necessary for scans */ divShift = prevCmd.divShift; modMask = (1 << divShift) - 1; // @Bug 2889. Drop partition enhancement. Read FilesPerColumnPartition and ExtentsPerSegmentFile for use // in RID calculation. fFilesPerColumnPartition = prevCmd.fFilesPerColumnPartition; // MCOL-4685 remove the option to set more than 2 extents per file (ExtentsPreSegmentFile). fExtentsPerSegmentFile = prevCmd.fExtentsPerSegmentFile; } ColumnCommandJL::~ColumnCommandJL() { } // The other leg is in PP, its name is ColumnCommand::makeCommand. void ColumnCommandJL::createCommand(ByteStream& bs) const { bs << (uint8_t)COLUMN_COMMAND; colType.serialize(bs); bs << (uint8_t)isScan; bs << traceFlags; if (isDict() && fContainsRanges) { // XXX: we should discern here between IS (NOT) NULL and other filters. ByteStream empty; auto zeroFC = filterCount; bs << empty; bs << BOP; zeroFC = 0; bs << zeroFC; } else { bs << filterString; bs << BOP; bs << filterCount; } if (hasAuxCol) bs << (uint8_t)1; else bs << (uint8_t)0; serializeInlineVector(bs, fLastLbid); CommandJL::createCommand(bs); } void ColumnCommandJL::runCommand(ByteStream& bs) const { bs << lbid; if (hasAuxCol) bs << lbidAux; } void ColumnCommandJL::setLBID(uint64_t rid, uint32_t dbRoot) { uint32_t partNum; uint16_t segNum; uint8_t extentNum; uint16_t blockNum; uint32_t colWidth; uint32_t i; idbassert(extents.size() > 0); colWidth = extents[0].colWid; rowgroup::getLocationFromRid(rid, &partNum, &segNum, &extentNum, &blockNum); for (i = 0; i < extents.size(); i++) { if (extents[i].dbRoot == dbRoot && extents[i].partitionNum == partNum && extents[i].segmentNum == segNum && extents[i].blockOffset == (extentNum * colWidth * 1024)) { lbid = extents[i].range.start + (blockNum * colWidth); currentExtentIndex = i; /* ostringstream os; os << "CCJL: rid=" << rid << "; dbroot=" << dbRoot << "; partitionNum=" << partNum << "; segmentNum=" << segNum << "; extentNum = " << (int) extentNum << "; blockNum = " << blockNum << "; OID=" << OID << " LBID=" << lbid; cout << os.str() << endl; */ break; } } if (i == extents.size()) { throw logic_error("ColumnCommandJL: setLBID didn't find the extent for the rid."); } uint32_t j; for (j = 0; j < extentsAux.size(); j++) { if (extentsAux[j].dbRoot == dbRoot && extentsAux[j].partitionNum == partNum && extentsAux[j].segmentNum == segNum && extentsAux[j].blockOffset == (extentNum * 1 * 1024)) { lbidAux = extentsAux[j].range.start + (blockNum * 1); break; } } if (hasAuxCol && j == extentsAux.size()) { throw logic_error("ColumnCommandJL: setLBID didn't find the extent for the rid."); } // ostringstream os; // os << "CCJL: rid=" << rid << "; dbroot=" << dbRoot << "; partitionNum=" << partitionNum << "; //segmentNum=" << segmentNum << "; stripeWithinPartition=" << stripeWithinPartition << "; OID=" << OID << " //LBID=" << lbid; BRM::log(os.str()); } inline uint32_t ColumnCommandJL::getFBO(uint64_t lbid) { uint32_t i; uint64_t lastLBID; for (i = 0; i < extents.size(); i++) { lastLBID = extents[i].range.start + (extents[i].range.size << 10) - 1; if (lbid >= (uint64_t)extents[i].range.start && lbid <= lastLBID) { // @Bug 2889. Change for drop partition. Treat the FBO as if all of the partitions are // still there as one or more partitions may have been dropped. Get the original index // for this partition (i.e. what the index would be if all of the partitions were still // there). The RIDs wind up being calculated off of this FBO for use in DML and DML // needs calculates the partition number, segment number, etc. off of the RID and needs // to remain the same when partitions are dropped. // // originalIndex = extents in partitions above + // extents in this partition in stripes above + // file offset in this stripe uint32_t originalIndex = (extents[i].partitionNum * fExtentsPerSegmentFile * fFilesPerColumnPartition) + ((extents[i].blockOffset / extents[i].colWid / 1024) * fFilesPerColumnPartition) + extents[i].segmentNum; return (lbid - extents[i].range.start) + (originalIndex << divShift); } } throw logic_error("ColumnCommandJL: didn't find the FBO?"); } uint8_t ColumnCommandJL::getTableColumnType() { switch (colType.colWidth) { case 8: return TableColumn::UINT64; case 4: return TableColumn::UINT32; case 2: return TableColumn::UINT16; case 1: return TableColumn::UINT8; // TODO MCOL-641 case 16: // fallthrough default: throw logic_error("ColumnCommandJL: bad column width"); } } string ColumnCommandJL::toString() { ostringstream ret; ret << "ColumnCommandJL: " << filterCount << " filters, BOP=" << ((int)BOP) << ", colwidth=" << colType.colWidth << " oid=" << OID << " name=" << colName; if (isScan) ret << " (scan)"; if (isDict()) ret << " (tokens)"; else if (datatypes::isCharType(colType.colDataType)) ret << " (is char)"; return ret.str(); } uint16_t ColumnCommandJL::getWidth() { return colType.colWidth; } void ColumnCommandJL::reloadExtents() { int err; BRM::DBRM dbrm; err = dbrm.getExtents(OID, extents); if (err) { ostringstream os; os << "pColStep: BRM lookup error. Could not get extents for OID " << OID; throw runtime_error(os.str()); } sort(extents.begin(), extents.end(), BRM::ExtentSorter()); if (hasAuxCol) { err = dbrm.getExtents(fOidAux, extentsAux); if (err) { ostringstream os; os << "BRM lookup error. Could not get extents for Aux OID " << fOidAux; throw runtime_error(os.str()); } sort(extentsAux.begin(), extentsAux.end(), BRM::ExtentSorter()); } } bool ColumnCommandJL::getIsDict() { return fIsDict; } }; // namespace joblist