Added .cpp and .h files under the sql/src subdirectory

git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@469 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
dsandersoremutah
2006-05-26 23:17:49 +00:00
parent dc6cd8b9cb
commit 021073907f
82 changed files with 97516 additions and 0 deletions

727
sql/src/btreeinfo.cpp Normal file
View File

@@ -0,0 +1,727 @@
//------------------------------------------------------------------------------
// Desc: Class for gathering b-tree information.
//
// Tabs: 3
//
// Copyright (c) 2005-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// 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, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: btreeinfo.cpp 3116 2006-01-19 13:31:53 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
/****************************************************************************
Desc: Collect information about a block.
****************************************************************************/
RCODE F_BTreeInfo::collectBlockInfo(
F_Db * pDb,
LFILE * pLFile,
BTREE_INFO * pBTreeInfo,
F_BTREE_BLK_HDR * pBlkHdr,
F_INDEX * pIndex)
{
RCODE rc = NE_SFLM_OK;
SFLM_BTREE_LEVEL_INFO * pLevelInfo = &pBTreeInfo->levelInfo [m_uiCurrLevel];
FLMUINT uiLoop;
FLMBYTE * pucOffset;
FLMBYTE * pucEntry;
FLMBYTE * pucTmp;
FLMUINT uiKeyLen;
FLMUINT uiDataLen;
F_CachedBlock * pCachedBlock = NULL;
FLMUINT uiBlkAddr;
FLMUINT uiOADataLen;
FLMBYTE * pucKey;
// Block level better be the same as our current level we are
// supposedly processing.
flmAssert( (FLMUINT)pBlkHdr->ui8BlkLevel == m_uiCurrLevel);
pLevelInfo->ui64BlockCount++;
pLevelInfo->ui64BlockLength += (FLMUINT64)m_uiBlockSize;
pLevelInfo->ui64ElmOffsetOverhead += ((FLMUINT64)pBlkHdr->ui16NumKeys * 2);
pLevelInfo->ui64ElmCount += (FLMUINT64)pBlkHdr->ui16NumKeys;
pLevelInfo->ui64BlockFreeSpace += pBlkHdr->stdBlkHdr.ui16BlkBytesAvail;
// Traverse through each key.
pucOffset = (FLMBYTE *)pBlkHdr + sizeofBTreeBlkHdr( pBlkHdr);
for (uiLoop = 0;
uiLoop < (FLMUINT)pBlkHdr->ui16NumKeys;
uiLoop++, pucOffset += 2)
{
pucEntry = ((FLMBYTE *)pBlkHdr) + FB2UW( pucOffset);
uiDataLen = 0;
uiOADataLen = 0;
uiKeyLen = 0;
switch (pBlkHdr->stdBlkHdr.ui8BlkType)
{
case BT_LEAF:
// Elements are:
// Key Length - 2 bytes
// Key - Key Length bytes
uiKeyLen = (FLMUINT)FB2UW( pucEntry);
pLevelInfo->ui64ElmKeyLengthOvhd += 2;
pucKey = pucEntry + 2;
break;
case BT_NON_LEAF:
// Elements are:
// Child Blk Address - 4 bytes
// Key Length - 2 bytes
// Key - Key Length bytes
pLevelInfo->ui64ElmChildAddrsOvhd += 4;
uiKeyLen = (FLMUINT)FB2UW( pucEntry + 4);
pLevelInfo->ui64ElmKeyLengthOvhd += 2;
pucKey = pucEntry + 6;
break;
case BT_NON_LEAF_COUNTS:
// Elements are:
// Child Block Address - 4 bytes
// Counts - 4 bytes
// Key Length - 2 bytes
// Key - Key Length bytes
uiKeyLen = (FLMUINT)FB2UW( pucEntry + 8);
pLevelInfo->ui64ElmKeyLengthOvhd += 2;
pLevelInfo->ui64ElmCountsOvhd += 4;
pLevelInfo->ui64ElmChildAddrsOvhd += 4;
pucKey = pucEntry + 10;
break;
case BT_LEAF_DATA:
// Elements are:
// Flags - 1 byte
// Key Length - 1 or 2 bytes
// Data Length - 1 or 2 bytes
// Overall data Length - 0 or 4 bytes
// Key - Key Length bytes
// Data - Data Length bytes. NOTE: May be a four byte blk
// address if data is stored in data-only blocks.
pLevelInfo->ui64ElmFlagOvhd++;
if (!(*pucEntry & BTE_FLAG_FIRST_ELEMENT))
{
pLevelInfo->ui64ContElmCount++;
}
pucTmp = pucEntry + 1;
if (bteKeyLenFlag( pucEntry))
{
// Two byte key length
uiKeyLen = (FLMUINT)FB2UW( pucTmp);
pLevelInfo->ui64ElmKeyLengthOvhd += 2;
pucTmp += 2;
}
else
{
// One byte key length
uiKeyLen = (FLMUINT)(*pucTmp);
pLevelInfo->ui64ElmKeyLengthOvhd++;
pucTmp++;
}
if (bteDataLenFlag( pucEntry))
{
// Two byte data length
uiDataLen = (FLMUINT)FB2UW( pucTmp);
pLevelInfo->ui64ElmDataLenOvhd += 2;
pucTmp += 2;
}
else
{
// One byte data length.
uiDataLen = (FLMUINT)(*pucTmp);
pLevelInfo->ui64ElmDataLenOvhd++;
pucTmp++;
}
// Check for the presence of the OverallDataLength field (4 bytes).
if (bteOADataLenFlag( pucEntry))
{
uiOADataLen = (FLMUINT)FB2UD( pucTmp);
pLevelInfo->ui64ElmOADataLenOvhd += 4;
pucTmp += 4;
}
pucKey = pucTmp;
if (bteDataBlockFlag( pucEntry))
{
flmAssert( uiDataLen == 4);
flmAssert( uiOADataLen);
// Skip over the key to get to the data only block address.
pucTmp += uiKeyLen;
uiBlkAddr = (FLMUINT)FB2UD( pucTmp);
while (uiBlkAddr)
{
if (RC_BAD( pDb->m_pDatabase->getBlock( pDb, pLFile,
uiBlkAddr, NULL, &pCachedBlock)))
{
goto Exit;
}
// Block better be a data-only block.
flmAssert( pCachedBlock->m_pBlkHdr->ui8BlkType == BT_DATA_ONLY);
pLevelInfo->ui64DataOnlyBlockCount++;
pLevelInfo->ui64DataOnlyBlockLength += (FLMUINT64)m_uiBlockSize;
pLevelInfo->ui64DataOnlyBlockFreeSpace +=
(FLMUINT64)pBlkHdr->stdBlkHdr.ui16BlkBytesAvail;
// Subtract from uiIODataLen - should go to exactly
// zero by the time we leave this loop.
uiOADataLen -= (m_uiBlockSize -
sizeofDOBlkHdr( pCachedBlock->m_pBlkHdr) -
pCachedBlock->m_pBlkHdr->ui16BlkBytesAvail);
uiBlkAddr = (FLMUINT)pCachedBlock->m_pBlkHdr->ui32NextBlkInChain;
ScaReleaseCache( pCachedBlock, FALSE);
pCachedBlock = NULL;
}
// Better have accounted for the exact amount of data that
// was given in the overall data length field.
flmAssert( !uiOADataLen);
}
break;
default:
pucKey = NULL;
flmAssert( 0);
break;
}
if (uiKeyLen)
{
pLevelInfo->ui64ElmKeyLength += (FLMUINT64)uiKeyLen;
}
if (uiDataLen)
{
pLevelInfo->ui64ElmDataLength += (FLMUINT64)uiDataLen;
}
// If this is an index, parse the key.
if (pIndex && uiKeyLen)
{
FLMUINT uiComponentLen;
FLMBYTE * pucKeyEnd = pucKey + uiKeyLen;
ICD * pIcd;
FLMUINT uiIcd;
for (uiIcd = 0, pIcd = pIndex->pKeyIcds;
uiIcd < pIndex->uiNumKeyComponents;
uiIcd++, pIcd++)
{
flmAssert( pucKey + 2 <= pucKeyEnd);
uiComponentLen = getKeyComponentLength( pucKey);
if (uiComponentLen == KEY_HIGH_VALUE ||
uiComponentLen == KEY_LOW_VALUE)
{
uiComponentLen = 0;
}
pLevelInfo->ui64KeyComponentLengthsSize += 2;
if (uiComponentLen)
{
pLevelInfo->ui64KeyDataSize += (FLMUINT64)uiComponentLen;
}
pucKey += (2 + uiComponentLen);
}
pLevelInfo->ui64KeyIdSize += (FLMUINT64)(pucKeyEnd - pucKey);
}
}
Exit:
if (pCachedBlock)
{
ScaReleaseCache( pCachedBlock, FALSE);
}
return( rc);
}
/****************************************************************************
Desc: Collect information on a b-tree.
****************************************************************************/
RCODE F_BTreeInfo::collectBTreeInfo(
F_Db * pDb,
LFILE * pLFile,
BTREE_INFO * pBTreeInfo,
const char * pszName,
F_INDEX * pIndex)
{
RCODE rc = NE_SFLM_OK;
FLMUINT uiNameBufSize;
FLMUINT uiLeftBlocks [MAX_LEVELS];
F_Database * pDatabase = pDb->m_pDatabase;
F_CachedBlock * pCachedBlock = NULL;
F_BTREE_BLK_HDR * pBlkHdr;
m_uiBlockSize = pDatabase->m_uiBlockSize;
// Allocate a name buffer.
uiNameBufSize = f_strlen( pszName) + 1;
if (RC_BAD( rc = m_pool.poolAlloc( uiNameBufSize,
(void **)(&pBTreeInfo->pszLfName))))
{
goto Exit;
}
f_strcpy( pBTreeInfo->pszLfName, pszName);
m_uiCurrLfNum = pLFile->uiLfNum;
m_bIsTable = pIndex ? FALSE : TRUE;
m_pszCurrLfName = pBTreeInfo->pszLfName;
// Reset the information for the b-tree. uiLfNum should have already
// been set by the caller.
flmAssert( pBTreeInfo->uiLfNum == pLFile->uiLfNum);
pBTreeInfo->uiNumLevels = 0;
f_memset( &pBTreeInfo->levelInfo [0], 0, sizeof( pBTreeInfo->levelInfo));
// Read the root block to see how many levels are in the b-tree.
if (RC_BAD( pDatabase->getBlock( pDb, pLFile, pLFile->uiRootBlk,
NULL, &pCachedBlock)))
{
goto Exit;
}
pBlkHdr = (F_BTREE_BLK_HDR *)pCachedBlock->m_pBlkHdr;
pBTreeInfo->uiNumLevels = pBlkHdr->ui8BlkLevel + 1;
flmAssert( pBTreeInfo->uiNumLevels <= MAX_LEVELS);
// Better be a root block, and better not have a prev and next
// block address.
flmAssert( isRootBlk( pBlkHdr));
flmAssert( pBlkHdr->stdBlkHdr.ui32BlkAddr == (FLMUINT32)pLFile->uiRootBlk);
flmAssert( !pBlkHdr->stdBlkHdr.ui32PrevBlkInChain);
flmAssert( !pBlkHdr->stdBlkHdr.ui32NextBlkInChain);
m_uiCurrLevel = pBlkHdr->ui8BlkLevel;
// Gather information for the root block.
if (RC_BAD( rc = collectBlockInfo( pDb, pLFile, pBTreeInfo,
pBlkHdr, pIndex)))
{
goto Exit;
}
m_ui64CurrLfBlockCount = 1;
m_ui64CurrLevelBlockCount = 1;
m_ui64TotalBlockCount = 1;
if (RC_BAD( rc = doCallback()))
{
goto Exit;
}
// Get all of the leftmost blocks in the b-tree.
uiLeftBlocks [pBlkHdr->ui8BlkLevel] = pLFile->uiRootBlk;
if (!pBlkHdr->ui8BlkLevel)
{
flmAssert( pBlkHdr->stdBlkHdr.ui8BlkType == BT_LEAF ||
pBlkHdr->stdBlkHdr.ui8BlkType == BT_LEAF_DATA);
}
else
{
FLMUINT uiLevel;
FLMBYTE * pucEntry;
FLMUINT uiBlkAddr;
// Gather up the leftmost blocks
uiLevel = pBlkHdr->ui8BlkLevel;
while (uiLevel)
{
uiLevel--;
// Get the left-most down-block pointer - which is the first one
// in the array.
pucEntry = ((FLMBYTE *)pBlkHdr) + sizeofBTreeBlkHdr( pBlkHdr);
pucEntry = ((FLMBYTE *)pBlkHdr) + FB2UW( pucEntry);
uiLeftBlocks [uiLevel] = (FLMUINT)FB2UD( pucEntry);
// Get the leftmost block at the next level down in the b-tree
ScaReleaseCache( pCachedBlock, FALSE);
pCachedBlock = NULL;
if (RC_BAD( pDatabase->getBlock( pDb, pLFile,
uiLeftBlocks [uiLevel], NULL, &pCachedBlock)))
{
goto Exit;
}
pBlkHdr = (F_BTREE_BLK_HDR *)pCachedBlock->m_pBlkHdr;
// If we are at level zero, we better be on a leaf block.
if (!uiLevel)
{
flmAssert( pBlkHdr->stdBlkHdr.ui8BlkType == BT_LEAF ||
pBlkHdr->stdBlkHdr.ui8BlkType == BT_LEAF_DATA);
}
}
// Now do each level of the b-tree. Have already done the root
// block, so we start one level down from it.
m_uiCurrLevel = pBTreeInfo->uiNumLevels - 2;
for (;;)
{
uiBlkAddr = uiLeftBlocks [m_uiCurrLevel];
m_ui64CurrLevelBlockCount = 0;
while (uiBlkAddr)
{
if (pCachedBlock)
{
ScaReleaseCache( pCachedBlock, FALSE);
pCachedBlock = NULL;
}
if (RC_BAD( pDatabase->getBlock( pDb, pLFile, uiBlkAddr,
NULL, &pCachedBlock)))
{
goto Exit;
}
pBlkHdr = (F_BTREE_BLK_HDR *)pCachedBlock->m_pBlkHdr;
// Gather information for the block.
if (RC_BAD( rc = collectBlockInfo( pDb, pLFile, pBTreeInfo,
pBlkHdr, pIndex)))
{
goto Exit;
}
m_ui64CurrLfBlockCount++;
m_ui64CurrLevelBlockCount++;
m_ui64TotalBlockCount++;
if (RC_BAD( rc = doCallback()))
{
goto Exit;
}
// Go to the next block in the chain.
uiBlkAddr = pBlkHdr->stdBlkHdr.ui32NextBlkInChain;
}
if (!m_uiCurrLevel)
{
break;
}
// Go down to the next level in the b-tree.
m_uiCurrLevel--;
}
}
Exit:
if (pCachedBlock)
{
ScaReleaseCache( pCachedBlock, FALSE);
}
return( rc);
}
/****************************************************************************
Desc: Collect b-tree information for an index. If uiIndexNum is zero,
collect b-tree information for ALL indexes.
If we already have information on the index, we will clear the
information and get it again.
****************************************************************************/
RCODE F_BTreeInfo::collectIndexInfo(
F_Db * pDb,
FLMUINT uiIndexNum,
IF_BTreeInfoStatus * pInfoStatus)
{
RCODE rc = NE_SFLM_OK;
FLMBOOL bStartedTrans = FALSE;
BTREE_INFO * pIndexInfo;
F_INDEX * pIndex;
FLMUINT uiLoop;
// Start a read transaction, if no other transaction is going.
if (pDb->getTransType() == SFLM_NO_TRANS)
{
if (RC_BAD( rc = pDb->transBegin( SFLM_READ_TRANS)))
{
goto Exit;
}
bStartedTrans = TRUE;
}
m_pInfoStatus = pInfoStatus;
m_uiCurrLfNum = 0;
m_bIsTable = FALSE;
m_pszCurrLfName = NULL;
m_uiCurrLevel = 0;
m_ui64CurrLfBlockCount = 0;
m_ui64CurrLevelBlockCount = 0;
m_ui64TotalBlockCount = 0;
if (!uiIndexNum)
{
m_uiNumIndexes = 0;
for (uiLoop = 0, pIndex = pDb->m_pDict->m_pIndexTbl;
uiLoop < pDb->m_pDict->m_uiHighestIndexNum;
uiLoop++, pIndex++)
{
if (pIndex->uiIndexNum)
{
if (RC_BAD( rc = collectIndexInfo( pDb, pIndex->uiIndexNum, pInfoStatus)))
{
goto Exit;
}
}
}
}
else
{
// See if we can find the b-tree already in our list.
uiLoop = 0;
pIndexInfo = m_pIndexArray;
while (uiLoop < m_uiNumIndexes && pIndexInfo->uiLfNum != uiIndexNum)
{
uiLoop++;
pIndexInfo++;
}
if (uiLoop == m_uiNumIndexes)
{
pIndexInfo = NULL;
}
// See if the index is defined in the database
if ((pIndex = pDb->m_pDict->getIndex( uiIndexNum)) == NULL)
{
rc = NE_SFLM_OK;
// If we previously had the index, remove it from the array.
if (pIndexInfo)
{
if (uiLoop < m_uiNumIndexes - 1)
{
f_memmove( pIndexInfo, &pIndexInfo[ 1],
sizeof( BTREE_INFO) * (m_uiNumIndexes - uiLoop - 1));
}
m_uiNumIndexes--;
}
goto Exit;
}
// If we previously had the index, reset its information.
// Otherwise, create a new index info structure and
// add it to the array.
if (!pIndexInfo)
{
// Allocate space for a new index info structure in the array.
if (m_uiNumIndexes == m_uiIndexArraySize)
{
if (RC_BAD( rc = f_realloc(
sizeof( BTREE_INFO) * (m_uiIndexArraySize + 5), &m_pIndexArray)))
{
goto Exit;
}
m_uiIndexArraySize += 5;
}
pIndexInfo = &m_pIndexArray [m_uiNumIndexes];
pIndexInfo->uiLfNum = uiIndexNum;
m_uiNumIndexes++;
}
// Get the index information
if (RC_BAD( rc = collectBTreeInfo( pDb, &pIndex->lfInfo, pIndexInfo,
pIndex->pszIndexName, pIndex)))
{
goto Exit;
}
}
Exit:
if (bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}
/****************************************************************************
Desc: Collect b-tree information for a collection. If uiTableNum is
zero, collect b-tree information for ALL collections.
If we already have information on the collection, we will clear the
information and get it again.
****************************************************************************/
RCODE F_BTreeInfo::collectTableInfo(
F_Db * pDb,
FLMUINT uiTableNum,
IF_BTreeInfoStatus * pInfoStatus)
{
RCODE rc = NE_SFLM_OK;
FLMBOOL bStartedTrans = FALSE;
BTREE_INFO * pTableInfo;
F_TABLE * pTable;
FLMUINT uiLoop;
// Start a read transaction, if no other transaction is going.
if (pDb->getTransType() == SFLM_NO_TRANS)
{
if (RC_BAD( rc = pDb->transBegin( SFLM_READ_TRANS)))
{
goto Exit;
}
bStartedTrans = TRUE;
}
m_pInfoStatus = pInfoStatus;
m_uiCurrLfNum = 0;
m_bIsTable = FALSE;
m_pszCurrLfName = NULL;
m_uiCurrLevel = 0;
m_ui64CurrLfBlockCount = 0;
m_ui64CurrLevelBlockCount = 0;
m_ui64TotalBlockCount = 0;
if (!uiTableNum)
{
m_uiNumTables = 0;
for (uiLoop = 0, pTable = pDb->m_pDict->m_pTableTbl;
uiLoop < pDb->m_pDict->m_uiHighestTableNum;
uiLoop++, pTable++)
{
if (pTable->uiTableNum)
{
if (RC_BAD( rc = collectTableInfo(
pDb, pTable->uiTableNum, pInfoStatus)))
{
goto Exit;
}
}
}
}
else
{
// See if we can find the b-tree already in our list.
uiLoop = 0;
pTableInfo = m_pTableArray;
while (uiLoop < m_uiNumTables && pTableInfo->uiLfNum != uiTableNum)
{
uiLoop++;
pTableInfo++;
}
if (uiLoop == m_uiNumTables)
{
pTableInfo = NULL;
}
// See if the index is defined in the database
if ((pTable = pDb->m_pDict->getTable( uiTableNum)) == NULL)
{
rc = NE_SFLM_OK;
// If we previously had the table, remove it from the array.
if (pTableInfo)
{
if (uiLoop < m_uiNumTables - 1)
{
f_memmove( pTableInfo, &pTableInfo[ 1],
sizeof( BTREE_INFO) * (m_uiNumTables - uiLoop - 1));
}
m_uiNumTables--;
}
goto Exit;
}
// If we previously had the table, reset its information.
// Otherwise, create a new table info structure and
// add it to the array.
if (!pTableInfo)
{
// Allocate space for a new index info structure in the array.
if (m_uiNumTables == m_uiTableArraySize)
{
if (RC_BAD( rc = f_realloc(
sizeof( BTREE_INFO) * (m_uiTableArraySize + 5),
&m_pTableArray)))
{
goto Exit;
}
m_uiTableArraySize += 5;
}
pTableInfo = &m_pTableArray [m_uiNumTables];
pTableInfo->uiLfNum = uiTableNum;
m_uiNumTables++;
}
// Get the table information
if (RC_BAD( rc = collectBTreeInfo( pDb, &pTable->lfInfo,
pTableInfo, pTable->pszTableName, NULL)))
{
goto Exit;
}
}
Exit:
if (bStartedTrans)
{
pDb->transAbort();
}
return( rc);
}