mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-06-01 22:41:43 +03:00
303 lines
11 KiB
C++
303 lines
11 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_extentstripealloc.cpp 4450 2013-01-21 14:13:24Z rdempsey $
|
||
*
|
||
******************************************************************************/
|
||
|
||
/** @file
|
||
* Contains class to allocate a "stripe" of extents for all columns across a tbl
|
||
*/
|
||
|
||
#include "we_extentstripealloc.h"
|
||
|
||
#include <iostream>
|
||
#include <sstream>
|
||
|
||
#include "we_define.h"
|
||
#include "we_log.h"
|
||
#include "we_brm.h"
|
||
|
||
namespace
|
||
{
|
||
typedef std::tr1::unordered_multimap<WriteEngine::OID,
|
||
WriteEngine::AllocExtEntry,
|
||
WriteEngine::AllocExtHasher> AllocExtMap;
|
||
typedef AllocExtMap::iterator AllocExtMapIter;
|
||
typedef AllocExtMap::const_iterator ConstAllocExtMapIter;
|
||
}
|
||
|
||
namespace WriteEngine
|
||
{
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Constructor
|
||
//------------------------------------------------------------------------------
|
||
ExtentStripeAlloc::ExtentStripeAlloc( OID tableOID,
|
||
Log* logger ) : fTableOID(tableOID), fLog(logger), fStripeCount(0)
|
||
{
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Destructor
|
||
// Note: fMap will automatically get cleared by unordered_map destructor,
|
||
// so no need to explicitly call clear() in "this" destructor.
|
||
//------------------------------------------------------------------------------
|
||
ExtentStripeAlloc::~ExtentStripeAlloc( )
|
||
{
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Add a column to be associated with the "stripe" allocations for "this"
|
||
// ExtentStripeAlloc object.
|
||
//------------------------------------------------------------------------------
|
||
void ExtentStripeAlloc::addColumn( OID colOID, int colWidth )
|
||
{
|
||
boost::mutex::scoped_lock lock(fMapMutex);
|
||
|
||
fColOIDs.push_back ( colOID );
|
||
fColWidths.push_back( colWidth );
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Allocate a "stripe" of column extents for the relevant table associated
|
||
// with the specified column OID, and at the specified DBRoot. The partition
|
||
// number, segment number, etc associated with the allocated extent are
|
||
// returned in the output arguments.
|
||
//
|
||
// Note that a multimap is used for the internal extent collection, with the
|
||
// column OID as the key. We would typically expect that we would not have
|
||
// more than 1 extent entry for a given column OID in our map at the same
|
||
// time. If this were always true, then a map (and not a multimap) would
|
||
// suffice.
|
||
// However, I suppose that if the read buffer were large enough, and the
|
||
// column widths small enough, then a parsing thread for a read buffer could
|
||
// end up asking for a "stripe" of extents "before" all the allocated extents
|
||
// for the previous read buffer have been used. In this case, we may end
|
||
// up needing to store more than 1 column extent for the same column, in
|
||
// our internal collection. Thus a multimap is used. To handle this case,
|
||
// we not only search the internal map for the specified column OID, but we
|
||
// also:
|
||
// 1. make sure we have an extent for the requested DBRoot
|
||
// 2. select the lowest allocated stripe, if there should be more than
|
||
// one column extent with the same DBRoot.
|
||
//------------------------------------------------------------------------------
|
||
int ExtentStripeAlloc::allocateExtent( OID oid,
|
||
uint16_t dbRoot,
|
||
uint32_t& partNum, // used as input for empty DBRoot, else output only
|
||
uint16_t& segNum,
|
||
BRM::LBID_t& startLbid,
|
||
int& allocSize,
|
||
HWM& hwm,
|
||
std::string& errMsg )
|
||
{
|
||
int retStatus = NO_ERROR;
|
||
bool bFound = false;
|
||
AllocExtMapIter extentEntryIter;
|
||
errMsg.clear();
|
||
|
||
std::pair<AllocExtMapIter,AllocExtMapIter> iters;
|
||
|
||
boost::mutex::scoped_lock lock(fMapMutex);
|
||
|
||
// Search for an extent matching the requested OID and DBRoot.
|
||
// We also filter by selecting the lowest stripe number. See
|
||
// function description that precedes this function for more detail.
|
||
iters = fMap.equal_range( oid );
|
||
if (iters.first != iters.second)
|
||
{
|
||
for (AllocExtMapIter it=iters.first; it!=iters.second; ++it)
|
||
{
|
||
if (it->second.fDbRoot == dbRoot)
|
||
{
|
||
if ((!bFound) ||
|
||
(it->second.fStripeKey <
|
||
extentEntryIter->second.fStripeKey))
|
||
{
|
||
extentEntryIter = it;
|
||
}
|
||
bFound = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Return selected extent
|
||
if (bFound)
|
||
{
|
||
partNum = extentEntryIter->second.fPartNum;
|
||
segNum = extentEntryIter->second.fSegNum;
|
||
startLbid = extentEntryIter->second.fStartLbid;
|
||
allocSize = extentEntryIter->second.fAllocSize;
|
||
hwm = extentEntryIter->second.fHwm;
|
||
errMsg = extentEntryIter->second.fStatusMsg;
|
||
retStatus = extentEntryIter->second.fStatus;
|
||
|
||
fMap.erase( extentEntryIter );
|
||
}
|
||
else // Allocate "stripe" of extents if there's no entry for this column OID
|
||
{
|
||
fStripeCount++;
|
||
|
||
std::ostringstream oss1;
|
||
oss1 << "Allocating next stripe(" << fStripeCount <<
|
||
") of column extents for table " << fTableOID <<
|
||
"; DBRoot-" << dbRoot;
|
||
fLog->logMsg( oss1.str(), MSGLVL_INFO2 );
|
||
|
||
std::vector<BRM::CreateStripeColumnExtentsArgIn> cols;
|
||
std::vector<BRM::CreateStripeColumnExtentsArgOut> extents;
|
||
for (unsigned int j=0; j<fColOIDs.size(); ++j)
|
||
{
|
||
BRM::CreateStripeColumnExtentsArgIn colEntry;
|
||
colEntry.oid = fColOIDs[j];
|
||
colEntry.width = fColWidths[j];
|
||
cols.push_back( colEntry );
|
||
}
|
||
|
||
uint32_t allocPartNum = partNum;
|
||
uint16_t allocSegNum = 0;
|
||
BRM::LBID_t allocStartLbid = 0;
|
||
int allocAllocSize = 0;
|
||
HWM allocHwm = 0;
|
||
int allocStatus = NO_ERROR;
|
||
std::string allocStatusMsg;
|
||
|
||
int rc = BRMWrapper::getInstance()->allocateStripeColExtents(
|
||
cols, dbRoot, allocPartNum, allocSegNum, extents );
|
||
|
||
// If allocation error occurs, we go ahead and store extent entries
|
||
// with error status, to satisfy subsequent allocations in same stripe.
|
||
if (rc != NO_ERROR)
|
||
{
|
||
for (unsigned int i=0; i<fColOIDs.size(); ++i)
|
||
{
|
||
if (oid != fColOIDs[i])
|
||
{
|
||
allocStatus = rc;
|
||
|
||
std::ostringstream oss;
|
||
oss << "Previous error allocating extent stripe for "
|
||
"table " << fTableOID << "; DBRoot: " << dbRoot;
|
||
allocStatusMsg = oss.str();
|
||
|
||
// For error case, just store 0 for part#,segnum, etc.
|
||
AllocExtEntry extentEntry(fColOIDs[i], fColWidths[i],
|
||
dbRoot, 0, 0, 0, 0, 0,
|
||
allocStatus, allocStatusMsg, fStripeCount );
|
||
|
||
fMap.insert( AllocExtMap::value_type(fColOIDs[i],
|
||
extentEntry) );
|
||
}
|
||
}
|
||
|
||
std::ostringstream oss;
|
||
oss << "Error allocating extent stripe for "
|
||
"table " << fTableOID << "; DBRoot: " << dbRoot;
|
||
errMsg = oss.str();
|
||
|
||
return rc;
|
||
}
|
||
|
||
// Save allocated extents into fMap for later use. For the OID
|
||
// requested by this function call, we just return the extent info.
|
||
for (unsigned int i=0; i<fColOIDs.size(); ++i)
|
||
{
|
||
allocStartLbid = extents[i].startLbid;
|
||
allocAllocSize = extents[i].allocSize;
|
||
allocHwm = extents[i].startBlkOffset;
|
||
|
||
// Might consider controlling this with debug, but we always
|
||
// log out for now.
|
||
//if (fLog->isDebug( DEBUG_1 ))
|
||
{
|
||
std::ostringstream oss;
|
||
oss << "Stripe Allocation: OID-" << fColOIDs[i] <<
|
||
"; DBRoot-" << dbRoot <<
|
||
"; Part#-" << allocPartNum <<
|
||
"; Seg#-" << allocSegNum <<
|
||
"; lbid-" << allocStartLbid <<
|
||
"; fbo-" << allocHwm <<
|
||
"; nblks-" << allocAllocSize;
|
||
fLog->logMsg( oss.str(), MSGLVL_INFO2 );
|
||
}
|
||
|
||
// Assign output args for requested column OID
|
||
if (oid == fColOIDs[i])
|
||
{
|
||
partNum = allocPartNum;
|
||
segNum = allocSegNum;
|
||
startLbid = allocStartLbid;
|
||
allocSize = allocAllocSize;
|
||
hwm = allocHwm;
|
||
}
|
||
else // Add all extents in "stripe" (other than requested column)
|
||
{ // to the collection of extents
|
||
AllocExtEntry extentEntry(fColOIDs[i], fColWidths[i],
|
||
dbRoot, allocPartNum, allocSegNum,
|
||
allocStartLbid, allocAllocSize, allocHwm,
|
||
allocStatus, allocStatusMsg, fStripeCount );
|
||
|
||
fMap.insert( AllocExtMap::value_type(fColOIDs[i],extentEntry) );
|
||
}
|
||
}
|
||
}
|
||
|
||
return retStatus;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
// Debug logging function to log contents of the allocated extents that are
|
||
// pending.
|
||
//------------------------------------------------------------------------------
|
||
void ExtentStripeAlloc::print( )
|
||
{
|
||
boost::mutex::scoped_lock lock(fMapMutex);
|
||
|
||
std::ostringstream oss;
|
||
oss << "Current Pending Extents for table " << fTableOID << ":";
|
||
|
||
if (fMap.size() > 0)
|
||
{
|
||
for (ConstAllocExtMapIter iter=fMap.begin();
|
||
iter!= fMap.end();
|
||
++iter)
|
||
{
|
||
oss << std::endl;
|
||
oss << " oid: " << iter->second.fOid <<
|
||
"; wid: " << iter->second.fColWidth <<
|
||
"; root: " << iter->second.fDbRoot <<
|
||
"; part: " << iter->second.fPartNum <<
|
||
"; seg: " << iter->second.fSegNum <<
|
||
"; lbid: " << iter->second.fStartLbid <<
|
||
"; size: " << iter->second.fAllocSize <<
|
||
"; hwm: " << iter->second.fHwm <<
|
||
"; stripe: " << iter->second.fStripeKey <<
|
||
"; stat: " << iter->second.fStatus <<
|
||
"; msg: " << iter->second.fStatusMsg;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
oss << " <EMPTY>";
|
||
}
|
||
|
||
fLog->logMsg( oss.str(), MSGLVL_INFO2 );
|
||
}
|
||
|
||
} //end of namespace
|