mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-20 09:07:44 +03:00
527 lines
16 KiB
C++
527 lines
16 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_dbfileop.cpp 4737 2013-08-14 20:45:46Z bwilkinson $
|
|
|
|
/** @file */
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <cstring>
|
|
using namespace std;
|
|
|
|
#include "we_chunkmanager.h"
|
|
|
|
#include "we_dbfileop.h"
|
|
|
|
#include "we_stats.h"
|
|
#include "IDBDataFile.h"
|
|
using namespace idbdatafile;
|
|
|
|
using namespace BRM;
|
|
|
|
namespace WriteEngine
|
|
{
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
DbFileOp::DbFileOp() : m_chunkManager(NULL)
|
|
{}
|
|
|
|
/**
|
|
* Default Destructor
|
|
*/
|
|
DbFileOp::~DbFileOp()
|
|
{}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* flush the cache
|
|
* PARAMETERS:
|
|
* none
|
|
* RETURN:
|
|
* NO_ERROR if success, otherwise if fail
|
|
***********************************************************/
|
|
int DbFileOp::flushCache()
|
|
{
|
|
BlockBuffer* curBuf;
|
|
|
|
if ( !Cache::getUseCache() )
|
|
return NO_ERROR;
|
|
|
|
for ( CacheMapIt it = Cache::m_writeList->begin();
|
|
it != Cache::m_writeList->end(); it++ )
|
|
{
|
|
curBuf = it->second;
|
|
RETURN_ON_ERROR( writeDBFile( (*curBuf).cb.file.pFile,
|
|
(*curBuf).block.data,
|
|
(*curBuf).block.lbid ) );
|
|
}
|
|
|
|
RETURN_ON_ERROR( Cache::flushCache() );
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* get an entry within a sub block
|
|
* NOTE: the difference with readSubBlockEntry is that
|
|
* getSubBlockEntry only works for buffer while
|
|
* readSubBlockEntry works for file and block
|
|
* PARAMETERS:
|
|
* blockBuf - the block buffer
|
|
* sbid - sub block id
|
|
* entryNo - entry no within sub block
|
|
* width - width in bytes
|
|
* pStruct - sturcture pointer
|
|
* RETURN:
|
|
* none
|
|
***********************************************************/
|
|
void DbFileOp::getSubBlockEntry( unsigned char* blockBuf,
|
|
const int sbid, const int entryNo,
|
|
const int width, void* pStruct )
|
|
{
|
|
unsigned char* pBlock;
|
|
|
|
pBlock = blockBuf + BYTE_PER_SUBBLOCK * sbid + entryNo * MAX_COLUMN_BOUNDARY;
|
|
memcpy( pStruct, pBlock, width );
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Read a block from a file at specified location
|
|
* PARAMETERS:
|
|
* pFile - file handle
|
|
* readBuf - read buffer
|
|
* fbo - file block offset
|
|
* RETURN:
|
|
* NO_ERROR if success
|
|
* other number if something wrong
|
|
***********************************************************/
|
|
int DbFileOp::readDBFile( IDBDataFile* pFile,
|
|
unsigned char* readBuf,
|
|
const uint64_t lbid,
|
|
const bool isFbo )
|
|
{
|
|
long long fboOffset = 0;
|
|
|
|
if ( !isFbo )
|
|
{
|
|
RETURN_ON_ERROR( setFileOffsetBlock( pFile, lbid ) );
|
|
}
|
|
else
|
|
{
|
|
fboOffset = (lbid) * (long)BYTE_PER_BLOCK;
|
|
RETURN_ON_ERROR( setFileOffset( pFile, fboOffset ) );
|
|
}
|
|
|
|
return readFile( pFile, readBuf, BYTE_PER_BLOCK );
|
|
}
|
|
|
|
int DbFileOp::readDBFile( IDBDataFile* pFile,
|
|
DataBlock* block,
|
|
const uint64_t lbid,
|
|
const bool isFbo )
|
|
{
|
|
block->dirty = false;
|
|
block->no = lbid;
|
|
|
|
Stats::incIoBlockRead();
|
|
|
|
return readDBFile( pFile, block->data, lbid, isFbo );
|
|
}
|
|
|
|
int DbFileOp::readDBFile( CommBlock& cb,
|
|
unsigned char* readBuf,
|
|
const uint64_t lbid )
|
|
{
|
|
CacheKey key;
|
|
|
|
if ( Cache::getUseCache() )
|
|
{
|
|
if ( Cache::cacheKeyExist( cb.file.oid, lbid ) )
|
|
{
|
|
key = Cache::getCacheKey( cb.file.oid, lbid );
|
|
RETURN_ON_ERROR( Cache::loadCacheBlock( key, readBuf ) );
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
RETURN_ON_ERROR( readDBFile( cb.file.pFile, readBuf, lbid ) );
|
|
|
|
if ( Cache::getUseCache() )
|
|
{
|
|
int fbo = lbid;
|
|
|
|
uint16_t dbRoot;
|
|
uint32_t partition;
|
|
uint16_t segment;
|
|
RETURN_ON_ERROR( BRMWrapper::getInstance()->getFboOffset(
|
|
lbid, dbRoot, partition, segment, fbo ) );
|
|
|
|
if ( Cache::getListSize( FREE_LIST ) == 0 )
|
|
{
|
|
if ( isDebug( DEBUG_1 ) )
|
|
{
|
|
printf( "\nBefore flushing cache " );
|
|
Cache::printCacheList();
|
|
}
|
|
|
|
// flush cache to give up more space
|
|
RETURN_ON_ERROR( flushCache() );
|
|
|
|
if ( isDebug( DEBUG_1 ) )
|
|
{
|
|
printf( "\nAfter flushing cache " );
|
|
Cache::printCacheList();
|
|
}
|
|
}
|
|
|
|
RETURN_ON_ERROR( Cache::insertLRUList( cb, lbid, fbo, readBuf ) );
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION: No change, old signature 10/17/06
|
|
* Read an entry within a sub block from a file
|
|
* NOTE: the difference with getSubBlockEntry is that
|
|
* getSubBlockEntry only works for buffer while
|
|
* readSubBlockEntry works for file and block
|
|
* PARAMETERS:
|
|
* pFile - file handler
|
|
* block - the block structure
|
|
* fbo - file block offset
|
|
* sbid - sub block id
|
|
* entryNo - entry no within sub block
|
|
* width - width in bytes
|
|
* pStruct - sturcture pointer
|
|
* RETURN:
|
|
* NO_ERROR if success
|
|
* other number if something wrong
|
|
***********************************************************/
|
|
const int DbFileOp::readSubBlockEntry( IDBDataFile* pFile, DataBlock* block,
|
|
const uint64_t lbid, const int sbid,
|
|
const int entryNo, const int width,
|
|
void* pStruct )
|
|
{
|
|
RETURN_ON_ERROR( readDBFile( pFile, block->data, lbid ) );
|
|
getSubBlockEntry( block->data, sbid, entryNo, width, pStruct );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
const int DbFileOp::readSubBlockEntry( CommBlock& cb, DataBlock* block,
|
|
const uint64_t lbid, const int sbid,
|
|
const int entryNo, const int width,
|
|
void* pStruct )
|
|
{
|
|
RETURN_ON_ERROR( readDBFile( cb, block->data, lbid ) );
|
|
getSubBlockEntry( block->data, sbid, entryNo, width, pStruct );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Set an entry within a sub block
|
|
* NOTE: the difference with writeSubBlockEntry is that
|
|
* setSubBlockEntry only works for buffer while
|
|
* writeSubBlockEntry works for file and block
|
|
* PARAMETERS:
|
|
* blockBuf - the block buffer
|
|
* sbid - sub block id
|
|
* entryNo - entry no within sub block
|
|
* width - width in bytes
|
|
* pStruct - sturcture pointer
|
|
* RETURN:
|
|
* none
|
|
***********************************************************/
|
|
void DbFileOp::setSubBlockEntry( unsigned char* blockBuf, const int sbid,
|
|
const int entryNo, const int width,
|
|
const void* pStruct )
|
|
{
|
|
unsigned char* pBlock;
|
|
|
|
pBlock = blockBuf + BYTE_PER_SUBBLOCK * sbid + entryNo * MAX_COLUMN_BOUNDARY;
|
|
memcpy( pBlock, pStruct, width );
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Write a number of blocks to the file at specified location
|
|
* PARAMETERS:
|
|
* pFile - file handle
|
|
* writeBuf - write buffer
|
|
* fbo - file block offset
|
|
* numOfBlock - total number of file block offset
|
|
* RETURN:
|
|
* NO_ERROR if success
|
|
* other number if something wrong
|
|
***********************************************************/
|
|
int DbFileOp::writeDBFile( CommBlock& cb, const unsigned char* writeBuf,
|
|
const uint64_t lbid, const int numOfBlock )
|
|
{
|
|
CacheKey key;
|
|
int ret;
|
|
|
|
if ( Cache::getUseCache() )
|
|
{
|
|
if ( Cache::cacheKeyExist( cb.file.oid, lbid ) )
|
|
{
|
|
key = Cache::getCacheKey( cb.file.oid, lbid );
|
|
RETURN_ON_ERROR( Cache::modifyCacheBlock( key, writeBuf ) );
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (BRMWrapper::getUseVb())
|
|
{
|
|
RETURN_ON_ERROR( writeVB( cb.file.pFile, cb.file.oid, lbid ) );
|
|
}
|
|
|
|
ret = writeDBFile( cb.file.pFile, writeBuf, lbid, numOfBlock );
|
|
|
|
if (BRMWrapper::getUseVb())
|
|
{
|
|
LBIDRange_v ranges;
|
|
LBIDRange range;
|
|
range.start = lbid;
|
|
range.size = 1;
|
|
ranges.push_back(range);
|
|
BRMWrapper::getInstance()->writeVBEnd(getTransId(), ranges);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int DbFileOp::writeDBFileNoVBCache(CommBlock& cb,
|
|
const unsigned char* writeBuf,
|
|
const int fbo,
|
|
const int numOfBlock)
|
|
{
|
|
return writeDBFileNoVBCache( cb.file.pFile, writeBuf, fbo, numOfBlock );
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Core function for writing data w/o using VB cache
|
|
* (bulk load dictionary store inserts)
|
|
***********************************************************/
|
|
int DbFileOp::writeDBFileNoVBCache( IDBDataFile* pFile,
|
|
const unsigned char* writeBuf,
|
|
const int fbo,
|
|
const int numOfBlock )
|
|
{
|
|
#ifdef PROFILE
|
|
// This function is only used by bulk load for dictionary store files,
|
|
// so we log as such.
|
|
Stats::startParseEvent(WE_STATS_WRITE_DCT);
|
|
#endif
|
|
|
|
for ( int i = 0; i < numOfBlock; i++ )
|
|
{
|
|
Stats::incIoBlockWrite();
|
|
RETURN_ON_ERROR( writeFile( pFile, writeBuf, BYTE_PER_BLOCK ) );
|
|
}
|
|
|
|
#ifdef PROFILE
|
|
Stats::stopParseEvent(WE_STATS_WRITE_DCT);
|
|
#endif
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Core function for writing data using VB cache
|
|
***********************************************************/
|
|
int DbFileOp::writeDBFile( IDBDataFile* pFile, const unsigned char* writeBuf,
|
|
const uint64_t lbid, const int numOfBlock )
|
|
{
|
|
RETURN_ON_ERROR( setFileOffsetBlock( pFile, lbid ) );
|
|
|
|
for ( int i = 0; i < numOfBlock; i++ )
|
|
{
|
|
Stats::incIoBlockWrite();
|
|
RETURN_ON_ERROR( writeFile( pFile, writeBuf, BYTE_PER_BLOCK ) );
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// just don't have a good solution to consolidate with above functions
|
|
// Note: This is used with absolute FBO, no lbid involved
|
|
int DbFileOp::writeDBFileFbo(IDBDataFile* pFile, const unsigned char* writeBuf,
|
|
const uint64_t fbo, const int numOfBlock )
|
|
{
|
|
long long fboOffset = 0;
|
|
|
|
fboOffset = (fbo) * (long)BYTE_PER_BLOCK;
|
|
RETURN_ON_ERROR( setFileOffset( pFile, fboOffset ) );
|
|
|
|
for ( int i = 0; i < numOfBlock; i++ )
|
|
{
|
|
Stats::incIoBlockWrite();
|
|
RETURN_ON_ERROR( writeFile( pFile, writeBuf, BYTE_PER_BLOCK ) );
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Write an entry within a sub block to a file
|
|
* NOTE: the difference with getSubBlockEntry is that
|
|
* setSubBlockEntry only works for buffer while
|
|
* writeSubBlockEntry works for file and block
|
|
* PARAMETERS:
|
|
* pFile - file handler
|
|
* block - the block structure
|
|
* fbo - file block offset
|
|
* sbid - sub block id
|
|
* entryNo - entry no within sub block
|
|
* width - width in bytes
|
|
* pStruct - sturcture pointer
|
|
* RETURN:
|
|
* NO_ERROR if success
|
|
* other number if something wrong
|
|
***********************************************************/
|
|
const int DbFileOp::writeSubBlockEntry( IDBDataFile* pFile, DataBlock* block,
|
|
const uint64_t lbid, const int sbid,
|
|
const int entryNo, const int width,
|
|
void* pStruct )
|
|
{
|
|
setSubBlockEntry( block->data, sbid, entryNo, width, pStruct );
|
|
block->dirty = false;
|
|
|
|
return writeDBFile( pFile, block->data, lbid );
|
|
}
|
|
|
|
const int DbFileOp::writeSubBlockEntry( CommBlock& cb, DataBlock* block,
|
|
const uint64_t lbid, const int sbid,
|
|
const int entryNo, const int width,
|
|
void* pStruct )
|
|
{
|
|
setSubBlockEntry( block->data, sbid, entryNo, width, pStruct );
|
|
block->dirty = false;
|
|
|
|
return writeDBFile( cb, block->data, lbid );
|
|
}
|
|
|
|
/***********************************************************
|
|
* DESCRIPTION:
|
|
* Write to version buffer
|
|
* PARAMETERS:
|
|
* oid - file oid
|
|
* lbid - lbid
|
|
* RETURN:
|
|
* NO_ERROR if success
|
|
* other number if something wrong
|
|
***********************************************************/
|
|
const int DbFileOp::writeVB( IDBDataFile* pFile, const OID oid, const uint64_t lbid )
|
|
{
|
|
if ( !BRMWrapper::getUseVb() )
|
|
return NO_ERROR;
|
|
|
|
int rc;
|
|
TxnID transId = getTransId();
|
|
|
|
if (transId != ((TxnID)INVALID_NUM))
|
|
{
|
|
rc = BRMWrapper::getInstance()->writeVB( pFile,
|
|
(const VER_t)transId,
|
|
oid, lbid, this );
|
|
//@Bug 4671. The error is already logged by worker node.
|
|
/* if (rc != NO_ERROR)
|
|
{
|
|
char msg[2048];
|
|
snprintf(msg, 2048,
|
|
"we_dbfileop->BRMWrapper::getInstance()->writeVB "
|
|
"transId %i oid %i lbid "
|
|
#if __LP64__
|
|
"%lu"
|
|
#else
|
|
"%llu"
|
|
#endif
|
|
" Error Code %i", transId, oid, lbid, rc);
|
|
puts(msg);
|
|
{
|
|
logging::MessageLog ml(logging::LoggingID(19));
|
|
logging::Message m;
|
|
logging::Message::Args args;
|
|
args.add(msg);
|
|
m.format(args);
|
|
ml.logCriticalMessage(m);
|
|
}
|
|
return rc;
|
|
} */
|
|
return rc;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int DbFileOp::readDbBlocks(IDBDataFile* pFile,
|
|
unsigned char* readBuf,
|
|
uint64_t fbo,
|
|
size_t n)
|
|
{
|
|
if (m_chunkManager)
|
|
{
|
|
return m_chunkManager->readBlocks(pFile, readBuf, fbo, n);
|
|
}
|
|
|
|
if (setFileOffset(pFile, fbo * BYTE_PER_BLOCK, SEEK_SET) != NO_ERROR)
|
|
return -1;
|
|
|
|
return pFile->read(readBuf, BYTE_PER_BLOCK * n) / BYTE_PER_BLOCK;
|
|
}
|
|
|
|
int DbFileOp::restoreBlock(IDBDataFile* pFile, const unsigned char* writeBuf, uint64_t fbo)
|
|
{
|
|
if (m_chunkManager)
|
|
return m_chunkManager->restoreBlock(pFile, writeBuf, fbo);
|
|
|
|
if (setFileOffset(pFile, fbo * BYTE_PER_BLOCK, SEEK_SET) != NO_ERROR)
|
|
return -1;
|
|
|
|
return pFile->write(writeBuf, BYTE_PER_BLOCK);
|
|
}
|
|
|
|
// @bug 5572 - HDFS usage: add *.tmp file backup flag
|
|
IDBDataFile* DbFileOp::getFilePtr(const Column& column, bool useTmpSuffix)
|
|
{
|
|
string filename;
|
|
return m_chunkManager->getFilePtr(column,
|
|
column.dataFile.fDbRoot,
|
|
column.dataFile.fPartition,
|
|
column.dataFile.fSegment,
|
|
filename,
|
|
"r+b",
|
|
column.colWidth,
|
|
useTmpSuffix);
|
|
}
|
|
|
|
} //end of namespace
|
|
|