git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@482 0109f412-320b-0410-ab79-c3e0c5ffbbe6
673 lines
13 KiB
C++
673 lines
13 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: FLAIM Dynamic search result set class.
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1998-2000, 2002-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$
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifndef FDYNSSET_H
|
|
#define FDYNSSET_H
|
|
|
|
/*****************************************************************************
|
|
*****
|
|
** Definitions
|
|
*****
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
A block size of 8K will perform well in minimizing the number of reads
|
|
to obtain a block. A 6K may perform better if the file is located
|
|
across the network.
|
|
*/
|
|
|
|
#define DYNSSET_BLOCK_SIZE 0x4000
|
|
#define DYNSSET_HASH_BUFFER_SIZE 0x2000
|
|
#define DYNSSET_MIN_FIXED_ENTRY_SIZE 4
|
|
// Change ucZeros in fdynsset.cpp if this changes.
|
|
#define DYNSSET_MAX_FIXED_ENTRY_SIZE 32
|
|
#define DYNSSET_POSITION_NOT_SET 0xFFFFFFFF
|
|
|
|
#define FBTREE_CACHE_BLKS 32
|
|
#define FBTREE_END 0xFFFFFFFF
|
|
#define FBTREE_MAX_LEVELS 4
|
|
|
|
typedef int (* FDYNSET_COMPARE_FUNC)(
|
|
void * pvData1,
|
|
void * pvData2,
|
|
void * pvUserData);
|
|
|
|
|
|
/*****************************************************************************
|
|
*****
|
|
** Forward References
|
|
*****
|
|
*****************************************************************************/
|
|
|
|
class FDynSearchSet;
|
|
class FHashBlk;
|
|
class FBtreeBlk;
|
|
class FBtreeRoot;
|
|
class FBtreeNonLeaf;
|
|
class FBtreeLeaf;
|
|
|
|
enum eBlkTypes
|
|
{
|
|
ACCESS_HASH,
|
|
ACCESS_BTREE_LEAF,
|
|
ACCESS_BTREE_ROOT,
|
|
ACCESS_BTREE_NON_LEAF
|
|
};
|
|
typedef enum eBlkTypes FBlkTypes;
|
|
|
|
|
|
/*===========================================================================
|
|
Virtual FFixedBlk
|
|
===========================================================================*/
|
|
class FFixedBlk : public F_Object
|
|
{
|
|
public:
|
|
|
|
FFixedBlk();
|
|
~FFixedBlk()
|
|
{
|
|
}
|
|
|
|
/* virtual methods that must be implemented */
|
|
|
|
FBlkTypes blkType()
|
|
{
|
|
return m_eBlkType;
|
|
}
|
|
|
|
virtual RCODE getCurrent(
|
|
void * pvEntryBuffer) = 0;
|
|
|
|
virtual RCODE getFirst(
|
|
void * pvEntryBuffer) = 0;
|
|
|
|
virtual RCODE getLast(
|
|
void * pvEntryBuffer) = 0;
|
|
|
|
virtual RCODE getNext(
|
|
void * pvEntryBuffer) = 0;
|
|
|
|
virtual FLMUINT getTotalEntries() = 0;
|
|
|
|
virtual RCODE insert(
|
|
void * pvEntry) = 0;
|
|
|
|
FINLINE FLMBOOL isDirty( void)
|
|
{
|
|
return( m_bDirty);
|
|
}
|
|
|
|
virtual RCODE search(
|
|
void * pvEntry,
|
|
void * pvFoundEntry = NULL) = 0;
|
|
|
|
void setCompareFunc(
|
|
FDYNSET_COMPARE_FUNC fnCompare,
|
|
void * pvUserData)
|
|
{
|
|
m_fnCompare = fnCompare;
|
|
m_pvUserData = pvUserData;
|
|
}
|
|
|
|
protected:
|
|
|
|
// Variables
|
|
|
|
FDYNSET_COMPARE_FUNC m_fnCompare;
|
|
void * m_pvUserData;
|
|
FBlkTypes m_eBlkType;
|
|
FLMUINT m_uiEntrySize;
|
|
FLMUINT m_uiNumSlots;
|
|
FLMUINT m_uiPosition;
|
|
FLMBOOL m_bDirty;
|
|
FLMBYTE * m_pucBlkBuf;
|
|
};
|
|
|
|
|
|
/*****************************************************************************
|
|
*****
|
|
** Result Set Class Definitions
|
|
** Source: fdynsset.cpp
|
|
*****
|
|
*****************************************************************************/
|
|
class FDynSearchSet : public F_Object
|
|
{
|
|
|
|
public:
|
|
|
|
FDynSearchSet()
|
|
{
|
|
m_fnCompare = NULL;
|
|
m_pvUserData = NULL;
|
|
m_uiEntrySize = 0;
|
|
m_pAccess = NULL;
|
|
}
|
|
|
|
~FDynSearchSet()
|
|
{
|
|
if (m_pAccess)
|
|
{
|
|
m_pAccess->Release();
|
|
}
|
|
}
|
|
|
|
RCODE setup(
|
|
char * pszTmpDir,
|
|
FLMUINT uiEntrySize);
|
|
|
|
FINLINE void setCompareFunc(
|
|
FDYNSET_COMPARE_FUNC fnCompare,
|
|
void * pvUserData
|
|
)
|
|
{
|
|
m_fnCompare = fnCompare;
|
|
m_pvUserData = pvUserData;
|
|
m_pAccess->setCompareFunc( fnCompare, pvUserData);
|
|
}
|
|
|
|
RCODE addEntry(
|
|
void * pvEntry);
|
|
|
|
FINLINE RCODE findMatch(
|
|
void * pvMatchEntry,
|
|
void * pvFoundEntry
|
|
)
|
|
{
|
|
return m_pAccess->search( pvMatchEntry, pvFoundEntry);
|
|
}
|
|
|
|
FINLINE FLMUINT getEntrySize( void)
|
|
{
|
|
return m_uiEntrySize;
|
|
}
|
|
|
|
FINLINE FLMUINT getTotalEntries( void)
|
|
{
|
|
return m_pAccess->getTotalEntries();
|
|
}
|
|
|
|
private:
|
|
|
|
// Variables
|
|
|
|
FDYNSET_COMPARE_FUNC m_fnCompare;
|
|
void * m_pvUserData;
|
|
FLMUINT m_uiEntrySize;
|
|
FFixedBlk * m_pAccess;
|
|
char m_szFileName [F_PATH_MAX_SIZE];
|
|
};
|
|
|
|
/*===========================================================================
|
|
Block Header Definition
|
|
|
|
Desc: Actually stored as the first section of each block.
|
|
We can write this structure because the same process will
|
|
read the block header i.e. portability is not a problem.
|
|
===========================================================================*/
|
|
|
|
typedef struct
|
|
{
|
|
FLMUINT uiBlkAddr;
|
|
FLMUINT uiPrevBlkAddr;
|
|
FLMUINT uiNextBlkAddr;
|
|
FLMUINT uiLEMAddr;
|
|
FLMUINT uiNumEntries;
|
|
} FixedBlkHdr;
|
|
|
|
/*===========================================================================
|
|
Fixed Length HASH Access Method
|
|
===========================================================================*/
|
|
class FHashBlk : public FFixedBlk
|
|
{
|
|
public:
|
|
|
|
FHashBlk()
|
|
{
|
|
// Base class constructors are called before this constructor is.
|
|
|
|
m_eBlkType = ACCESS_HASH;
|
|
m_pucBlkBuf = m_ucHashBlk;
|
|
f_memset( m_ucHashBlk, 0, sizeof( m_ucHashBlk));
|
|
m_uiTotalEntries = 0;
|
|
}
|
|
|
|
~FHashBlk()
|
|
{
|
|
// Set to NULL so we don't free the block
|
|
m_pucBlkBuf = NULL;
|
|
}
|
|
|
|
FINLINE RCODE setup(
|
|
FLMUINT uiEntrySize
|
|
)
|
|
{
|
|
m_uiEntrySize = uiEntrySize;
|
|
m_uiNumSlots = DYNSSET_HASH_BUFFER_SIZE / uiEntrySize;
|
|
return( NE_SFLM_OK);
|
|
}
|
|
|
|
FINLINE RCODE getCurrent(
|
|
void * pvEntryBuffer
|
|
)
|
|
{
|
|
|
|
// Position to the next/first entry.
|
|
|
|
if (m_uiPosition == DYNSSET_POSITION_NOT_SET)
|
|
{
|
|
return RC_SET( NE_SFLM_NOT_FOUND);
|
|
}
|
|
|
|
f_memcpy( pvEntryBuffer, &m_pucBlkBuf[ m_uiPosition], m_uiEntrySize);
|
|
return( NE_SFLM_OK);
|
|
}
|
|
|
|
FINLINE RCODE getFirst(
|
|
void * pvEntryBuffer
|
|
)
|
|
{
|
|
m_uiPosition = DYNSSET_POSITION_NOT_SET;
|
|
return( getNext( pvEntryBuffer));
|
|
}
|
|
|
|
RCODE getLast(
|
|
void * pvEntryBuffer);
|
|
|
|
RCODE getNext(
|
|
void * pvEntryBuffer);
|
|
|
|
FINLINE FLMUINT getTotalEntries( void)
|
|
{
|
|
return m_uiTotalEntries;
|
|
}
|
|
|
|
RCODE insert(
|
|
void * pvEntry);
|
|
|
|
RCODE search(
|
|
void * pvEntry,
|
|
void * pvFoundEntry = NULL);
|
|
|
|
private:
|
|
|
|
FLMUINT m_uiTotalEntries;
|
|
// Allocate the hash block to save 1 allocation.
|
|
// We need to make the hash as fast as possible.
|
|
FLMBYTE m_ucHashBlk[ DYNSSET_HASH_BUFFER_SIZE];
|
|
};
|
|
|
|
|
|
/*===========================================================================
|
|
Virtual FBtreeBlk
|
|
===========================================================================*/
|
|
|
|
// Leaf and non-leaf entry position. Don't do any ++ or -- ! ! ! !
|
|
|
|
#define ENTRY_POS(uiPos) (m_pucBlkBuf + sizeof( FixedBlkHdr) + \
|
|
(uiPos * (m_uiEntrySize+m_uiEntryOvhd)))
|
|
|
|
class FBtreeBlk : public FFixedBlk
|
|
{
|
|
public:
|
|
|
|
FBtreeBlk()
|
|
{
|
|
}
|
|
|
|
~FBtreeBlk()
|
|
{
|
|
if (m_pucBlkBuf)
|
|
{
|
|
f_free( &m_pucBlkBuf);
|
|
}
|
|
}
|
|
|
|
// virtual methods that must be implemented
|
|
|
|
FINLINE RCODE getCurrent(
|
|
void * pvEntryBuffer
|
|
)
|
|
{
|
|
// Position to the next/first entry.
|
|
|
|
if (m_uiPosition == DYNSSET_POSITION_NOT_SET)
|
|
{
|
|
return RC_SET( NE_SFLM_NOT_FOUND);
|
|
}
|
|
|
|
f_memcpy( pvEntryBuffer, ENTRY_POS( m_uiPosition), m_uiEntrySize);
|
|
return( NE_SFLM_OK);
|
|
}
|
|
|
|
FINLINE RCODE getFirst(
|
|
void * pvEntryBuffer
|
|
)
|
|
{
|
|
m_uiPosition = DYNSSET_POSITION_NOT_SET;
|
|
return( getNext( pvEntryBuffer));
|
|
}
|
|
|
|
RCODE getLast(
|
|
void * pvEntryBuffer);
|
|
|
|
RCODE getNext(
|
|
void * pvEntryBuffer);
|
|
|
|
RCODE readBlk(
|
|
IF_FileHdl * pFileHdl,
|
|
FLMUINT uiBlkAddr);
|
|
|
|
void reset(
|
|
FBlkTypes eBlkType);
|
|
|
|
RCODE split(
|
|
FBtreeRoot * pParent,
|
|
FLMBYTE * pucCurEntry,
|
|
FLMUINT uiCurBlkAddr,
|
|
FLMBYTE * pucParentEntry,
|
|
FLMUINT * puiNewBlkAddr);
|
|
|
|
RCODE writeBlk(
|
|
IF_FileHdl * pFileHdl);
|
|
|
|
// Virtual methods
|
|
|
|
virtual FLMUINT getTotalEntries( void) = 0;
|
|
|
|
virtual RCODE insert(
|
|
void * pvEntry) = 0;
|
|
|
|
virtual RCODE search(
|
|
void * pvEntry,
|
|
void * pvFoundEntry = NULL) = 0;
|
|
|
|
virtual RCODE searchEntry(
|
|
void * pvEntry,
|
|
FLMUINT * puiChildAddr = NULL,
|
|
void * pvFoundEntry = NULL);
|
|
|
|
// Implemented as inline functions.
|
|
// Even though these are b-tree specific - keep them here to
|
|
// avoid having a b-tree block class. Most are not used for hash.
|
|
|
|
FINLINE FLMUINT blkAddr( void)
|
|
{
|
|
return( ((FixedBlkHdr *)m_pucBlkBuf)->uiBlkAddr);
|
|
}
|
|
|
|
FINLINE void blkAddr(
|
|
FLMUINT uiBlkAddr)
|
|
{
|
|
((FixedBlkHdr *)m_pucBlkBuf)->uiBlkAddr = uiBlkAddr;
|
|
m_bDirty = TRUE;
|
|
}
|
|
|
|
// Get and set the number of entries in the block
|
|
|
|
FINLINE FLMUINT entryCount( void)
|
|
{
|
|
return( ((FixedBlkHdr *)m_pucBlkBuf)->uiNumEntries);
|
|
}
|
|
|
|
FINLINE void entryCount(
|
|
FLMUINT uiNumEntries)
|
|
{
|
|
((FixedBlkHdr *)m_pucBlkBuf)->uiNumEntries = uiNumEntries;
|
|
m_bDirty = TRUE;
|
|
}
|
|
|
|
RCODE insertEntry(
|
|
void * pvEntry,
|
|
FLMUINT uiChildAddr = FBTREE_END);
|
|
|
|
|
|
// Get and set the last element marker in the block.
|
|
|
|
FINLINE FLMUINT lemBlk( void)
|
|
{
|
|
return( ((FixedBlkHdr *)m_pucBlkBuf)->uiLEMAddr);
|
|
}
|
|
|
|
FINLINE void lemBlk(
|
|
FLMUINT uiLEMAddr)
|
|
{
|
|
((FixedBlkHdr *)m_pucBlkBuf)->uiLEMAddr = uiLEMAddr;
|
|
m_bDirty = TRUE;
|
|
}
|
|
|
|
// Get and set the next block address element
|
|
|
|
FINLINE FLMUINT nextBlk( void)
|
|
{
|
|
return( ((FixedBlkHdr *)m_pucBlkBuf)->uiNextBlkAddr);
|
|
}
|
|
|
|
FINLINE void nextBlk(
|
|
FLMUINT uiBlkAddr)
|
|
{
|
|
((FixedBlkHdr *)m_pucBlkBuf)->uiNextBlkAddr = uiBlkAddr;
|
|
m_bDirty = TRUE;
|
|
}
|
|
|
|
// Get and set the previous block address element
|
|
|
|
FINLINE FLMUINT prevBlk( void)
|
|
{
|
|
return( ((FixedBlkHdr *)m_pucBlkBuf)->uiPrevBlkAddr);
|
|
}
|
|
|
|
FINLINE void prevBlk(
|
|
FLMUINT uiBlkAddr)
|
|
{
|
|
((FixedBlkHdr *)m_pucBlkBuf)->uiPrevBlkAddr = uiBlkAddr;
|
|
m_bDirty = TRUE;
|
|
}
|
|
|
|
protected:
|
|
|
|
// Variables
|
|
|
|
FLMUINT m_uiEntryOvhd; // Overhead in the entry.
|
|
};
|
|
|
|
|
|
/*===========================================================================
|
|
Fixed Length B-tree Leaf - may be a root
|
|
===========================================================================*/
|
|
|
|
class FBtreeLeaf : public FBtreeBlk
|
|
{
|
|
public:
|
|
|
|
FBtreeLeaf()
|
|
{
|
|
m_eBlkType = ACCESS_BTREE_LEAF;
|
|
m_uiEntryOvhd = 0;
|
|
}
|
|
|
|
~FBtreeLeaf()
|
|
{
|
|
}
|
|
|
|
RCODE setup(
|
|
FLMUINT uiEntrySize);
|
|
|
|
FINLINE FLMUINT getTotalEntries( void)
|
|
{
|
|
return( (FLMUINT)entryCount());
|
|
}
|
|
|
|
FINLINE RCODE insert(
|
|
void * pvEntry)
|
|
{
|
|
return( insertEntry( pvEntry, FBTREE_END));
|
|
}
|
|
|
|
FINLINE RCODE search(
|
|
void * pvEntry,
|
|
void * pvFoundEntry = NULL)
|
|
{
|
|
return( searchEntry( pvEntry, NULL, pvFoundEntry));
|
|
}
|
|
|
|
RCODE split(
|
|
FBtreeRoot * pNewRoot);
|
|
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
FLMUINT uiBlkAddr;
|
|
FLMUINT uiLRUValue;
|
|
FBtreeBlk * pBlk; // Points to leaf or non-leaf block
|
|
} FBTREE_CACHE;
|
|
|
|
/*===========================================================================
|
|
Fixed Length B-tree non-leaf block
|
|
===========================================================================*/
|
|
|
|
class FBtreeNonLeaf : public FBtreeBlk
|
|
{
|
|
public:
|
|
|
|
FBtreeNonLeaf()
|
|
{
|
|
m_eBlkType = ACCESS_BTREE_NON_LEAF;
|
|
m_uiEntryOvhd = sizeof( FLMUINT32);
|
|
}
|
|
|
|
~FBtreeNonLeaf()
|
|
{
|
|
}
|
|
|
|
RCODE setup(
|
|
FLMUINT uiEntrySize);
|
|
|
|
FINLINE FLMUINT getTotalEntries( void)
|
|
{
|
|
return( (FLMUINT) entryCount());
|
|
}
|
|
|
|
FINLINE RCODE insert(
|
|
void * // pvEntry
|
|
)
|
|
{
|
|
return( NE_SFLM_OK);
|
|
}
|
|
|
|
FINLINE RCODE search(
|
|
void *, // pvEntry,
|
|
void * pvFoundEntry = NULL
|
|
)
|
|
{
|
|
F_UNREFERENCED_PARM( pvFoundEntry);
|
|
flmAssert( 0);
|
|
return( NE_SFLM_OK);
|
|
}
|
|
};
|
|
|
|
/*===========================================================================
|
|
Fixed Length B-tree Non-Leaf Root
|
|
===========================================================================*/
|
|
class FBtreeRoot : public FBtreeNonLeaf
|
|
{
|
|
public:
|
|
FBtreeRoot();
|
|
~FBtreeRoot();
|
|
|
|
RCODE setup(
|
|
FLMUINT uiEntrySize,
|
|
char * pszFileName);
|
|
|
|
|
|
void closeFile( void);
|
|
|
|
FINLINE FLMUINT getTotalEntries( void)
|
|
{
|
|
return( m_uiTotalEntries);
|
|
}
|
|
|
|
RCODE insert(
|
|
void * pvEntry);
|
|
|
|
RCODE newBlk(
|
|
FBtreeBlk ** ppBlk,
|
|
FBlkTypes eBlkType);
|
|
|
|
FINLINE FLMUINT newBlkAddr( void)
|
|
{
|
|
return( m_uiNewBlkAddr++);
|
|
}
|
|
|
|
RCODE newCacheBlk(
|
|
FLMUINT uiCachePos,
|
|
FBtreeBlk ** ppBlk,
|
|
FBlkTypes eBlkType);
|
|
|
|
RCODE openFile( void);
|
|
|
|
RCODE readBlk(
|
|
FLMUINT uiBlkAddr,
|
|
FBlkTypes eBlkType,
|
|
FBtreeBlk ** ppBlk);
|
|
|
|
RCODE search(
|
|
void * pvEntry,
|
|
void * pvFoundEntry = NULL);
|
|
|
|
RCODE setupTree(
|
|
FLMBYTE * pucMidEntry, // If !NULL entry to insert into root.
|
|
FBlkTypes eBlkType, // Leaf or non-leaf
|
|
FBtreeBlk ** ppLeftBlk, // (out)
|
|
FBtreeBlk ** ppRightBlk); // (out)
|
|
|
|
RCODE split(
|
|
void * pvCurEntry,
|
|
FLMUINT uiCurChildAddr);
|
|
|
|
RCODE writeBlk(
|
|
FLMUINT uiWritePos);
|
|
|
|
private:
|
|
|
|
FLMUINT m_uiLevels; // Number of levels in the b-tree
|
|
FLMUINT m_uiTotalEntries; // Count of total entries
|
|
FLMUINT m_uiNewBlkAddr; // Next new blk addr.
|
|
FLMUINT m_uiHighestWrittenBlkAddr;
|
|
|
|
IF_FileHdl * m_pFileHdl; // File handle or NULL if not open.
|
|
char * m_pszFileName; // File created for result set or default.
|
|
|
|
// Cache of 'n' blocks to apply LRU algorithm.
|
|
|
|
FLMUINT m_uiLRUCount; // Count to find least rec. used.
|
|
FBTREE_CACHE m_CacheBlks[ FBTREE_CACHE_BLKS];
|
|
|
|
// B-tree stack.
|
|
FBtreeBlk * m_BTStack[ FBTREE_MAX_LEVELS];
|
|
};
|
|
|
|
#endif // ifndef FRSET_H
|