|
|
//***************************************************************************
//
// (c) 2000 Microsoft Corp. All Rights Reserved.
//
// BTR.H
//
// Repository B-tree classes
//
// raymcc 15-Oct-00 First version
//
//***************************************************************************
#ifndef _BTR_H_
#define _BTR_H_
#define A51_INDEX_FILE_ID 2
class CPageFile; class CPageSource;
LPVOID WINAPI _BtrMemAlloc( SIZE_T dwBytes // number of bytes to allocate
);
LPVOID WINAPI _BtrMemReAlloc( LPVOID pOriginal, DWORD dwNewBytes );
BOOL WINAPI _BtrMemFree(LPVOID pMem);
#define ReleaseIfNotNULL(p) if(p) p->Release()
class CBTreeFile { DWORD m_dwPageSize;
DWORD m_dwLogicalRoot;
CPageFile* m_pFile; CPageSource *m_pTransactionManager;
// Methods
DWORD Setup(); DWORD WriteAdminPage();
public: CBTreeFile(); ~CBTreeFile();
enum { const_DefaultPageSize = 0x2000, const_CurrentVersion = 0x101 };
enum { PAGE_TYPE_IMPOSSIBLE = 0x0, // Not supposed to happen
PAGE_TYPE_ACTIVE = 0xACCC, // Page is active with data
PAGE_TYPE_DELETED = 0xBADD, // A deleted page on free list
PAGE_TYPE_ADMIN = 0xADDD, // Page zero only
// All pages
OFFSET_PAGE_TYPE = 0, // True for all pages
OFFSET_PAGE_ID = 1, // True for all pages
OFFSET_NEXT_PAGE = 2, // True for all pages (Page continuator)
// Admin Page (page zero) only
OFFSET_LOGICAL_ROOT = 3, // Root of database
};
DWORD Init( DWORD dwPageSize, // 8k default
LPWSTR pszFilename, CPageSource* pSource );
DWORD Shutdown(DWORD dwShutDownFlags);
DWORD GetPage(DWORD dwId, LPVOID *pPage); DWORD PutPage(LPVOID pPage, DWORD dwType); DWORD NewPage(LPVOID *pPage); DWORD FreePage(LPVOID pPage); DWORD FreePage(DWORD dwId);
DWORD GetPageSize() { return m_dwPageSize; }
DWORD SetRootPage(DWORD dwID); DWORD GetRootPage() { return m_dwLogicalRoot; } DWORD ReadAdminPage();
void Dump(FILE *); };
struct SIdxStringPool { DWORD m_dwNumStrings; // Number of strings in pool
WORD *m_pwOffsets; // Offsets into pool of strings
DWORD m_dwOffsetsSize; // Number of elements in above array
LPSTR m_pStringPool; // Pointer to string pool
DWORD m_dwPoolTotalSize; // Total size, used+unused
DWORD m_dwPoolUsed; // Offset of first free position
public: enum { const_DefaultPoolSize = 0x2200 };
SIdxStringPool() { memset(this, 0, sizeof(SIdxStringPool)); } ~SIdxStringPool();
DWORD AddStr(LPSTR pszStr, WORD wInsertPos, int *pnAdjuster); DWORD DeleteStr(WORD wAssignedOffset, int *pnAdjuster);
DWORD GetLastId() { return m_dwNumStrings; }
DWORD FindStr( IN LPSTR pszSearchKey, OUT WORD *pwStringNumber, OUT WORD *pwPoolOffset );
DWORD GetNumStrings() { return m_dwNumStrings; } DWORD GetRequiredPageMemory() { return m_dwPoolUsed + (m_dwNumStrings * sizeof(WORD)) + sizeof(m_dwNumStrings) + sizeof(m_dwPoolUsed); }
DWORD Dump(FILE *f);
LPSTR GetStrById(WORD id) { return m_pStringPool+m_pwOffsets[id]; } void Empty() { m_dwNumStrings = 0; m_dwPoolUsed = 0; } DWORD Clone(SIdxStringPool **); };
class SIdxKeyTable { DWORD m_dwRefCount; // Ref count
DWORD m_dwPageId; // Page number
DWORD m_dwParentPageId; // Parent page id <For DEBUGGING only>
DWORD m_dwNumKeys; // Num keys
WORD *m_pwKeyLookup; // Offset of key into key-encoding-table
DWORD m_dwKeyLookupTotalSize; // Elements in array
DWORD *m_pdwUserData; // User DWORD with each key
DWORD *m_pdwChildPageMap; // Child page pointers n=left ptr, n+1=right pointer
WORD *m_pwKeyCodes; // Key encoding table
DWORD m_dwKeyCodesTotalSize; // Total elements in array
DWORD m_dwKeyCodesUsed; // Elements used
SIdxStringPool *m_pStrPool; // The pool associated with this key table
// Methods
SIdxKeyTable(); ~SIdxKeyTable();
public: enum { const_DefaultArray = 256, const_DefaultKeyCodeArray = 512 };
static DWORD Create(DWORD dwPageId, SIdxKeyTable **pNew); static DWORD Create(LPVOID pPage, SIdxKeyTable **pNew);
DWORD AddRef(); DWORD Release();
DWORD AddKey(LPSTR pszStr, WORD ID, DWORD dwUserData); DWORD RemoveKey(WORD wID); DWORD FindKey(LPSTR pszStr, WORD *pID); DWORD GetUserData(WORD wID) { return m_pdwUserData[wID]; }
void SetChildPage(WORD wID, DWORD dwPage) { m_pdwChildPageMap[wID] = dwPage; } DWORD GetChildPage(WORD wID) { return m_pdwChildPageMap[wID]; } DWORD GetLastChildPage() { return m_pdwChildPageMap[m_dwNumKeys]; } DWORD GetLeftSiblingOf(DWORD dwId); DWORD GetRightSiblingOf(DWORD dwId); DWORD GetKeyAt(WORD wID, LPSTR *pszKey); // Use _MemFree
DWORD GetNumKeys() { return m_dwNumKeys; } void SetStringPool(SIdxStringPool *pPool) { m_pStrPool = pPool; } void FreeMem(LPVOID pMem);
void AdjustKeyCodes( WORD wID, int nAdjustment );
int KeyStrCompare( LPSTR pszSearchKey, WORD wID );
DWORD Cleanup();
DWORD NumKeys() { return m_dwNumKeys; } DWORD GetRequiredPageMemory(); DWORD Dump(FILE *, DWORD *pdwKeys = 0); void ZapPage(); DWORD GetPageId() { return m_dwPageId; }
// Sibling/Parent page helpers
DWORD GetKeyOverhead(WORD wID); // Returns total bytes required by new key
BOOL IsLeaf() { return m_pdwChildPageMap[0] == 0; } DWORD Redist( SIdxKeyTable *pParent, SIdxKeyTable *pNewSibling );
DWORD Collapse( SIdxKeyTable *pParent, SIdxKeyTable *pDoomedSibling );
DWORD StealKeyFromSibling( SIdxKeyTable *pParent, SIdxKeyTable *pSibling );
DWORD MapFromPage(LPVOID pSrc); DWORD MapToPage(LPVOID pMem);
DWORD Clone(OUT SIdxKeyTable **pCopy); };
class CBTree;
class CBTreeIterator { friend class CBTree; enum { const_MaxStack = 1024, const_PrefetchSize = 64 };
CBTree *m_pTree; SIdxKeyTable *m_Stack[const_MaxStack]; WORD m_wStack[const_MaxStack]; LONG m_lStackPointer;
LPSTR *m_pPrefetchKeys[const_PrefetchSize]; DWORD m_dwPrefetchData[const_PrefetchSize]; DWORD m_dwPrefetchActive;
~CBTreeIterator();
// Stack helpers
SIdxKeyTable *Peek() { return m_Stack[m_lStackPointer]; } WORD PeekId() { return m_wStack[m_lStackPointer]; } void IncStackId() { m_wStack[m_lStackPointer]++; }
void Pop() { ReleaseIfNotNULL(m_Stack[m_lStackPointer]); m_lStackPointer--; } BOOL StackFull() { return m_lStackPointer == const_MaxStack - 1; } void Push(SIdxKeyTable *p, WORD wId) { m_Stack[++m_lStackPointer] = p; m_wStack[m_lStackPointer] = wId; }
DWORD ZapStack(); DWORD PurgeKey(LPSTR pszDoomedKey); DWORD RebuildStack(LPSTR pszStartKey); DWORD ExecPrefetch();
static DWORD ZapAllStacks(); static DWORD GlobalPurgeKey(LPSTR pszDoomedKey);
public:
CBTreeIterator() { m_pTree = 0; m_lStackPointer = -1; }
DWORD Init(CBTree *pRoot, LPSTR pszStartKey = 0); // If last parm is null, iterate through all
DWORD Next(LPSTR *ppszStr, DWORD *pdwData = 0); void FreeString(LPSTR pszStr) { _BtrMemFree(pszStr); } DWORD Release(); };
class CBTree { enum { const_DefaultArray = 256 }; enum { const_MinimumLoad = 33 };
CBTreeFile *m_pSrc; SIdxKeyTable *m_pRoot; friend class CBTreeIterator;
LONG m_lGeneration;
// private methods
DWORD ReplaceBySuccessor( IN SIdxKeyTable *pIdx, IN WORD wId, OUT LPSTR *pszSuccessorKey, OUT BOOL *pbUnderflowDetected, DWORD Stack[], LONG &StackPtr );
DWORD FindSuccessorNode( IN SIdxKeyTable *pIdx, IN WORD wId, OUT SIdxKeyTable **pSuccessor, OUT DWORD *pdwPredecessorChild, DWORD Stack[], LONG &StackPtr );
DWORD ReadIdxPage( DWORD dwPage, SIdxKeyTable **pIdx );
DWORD WriteIdxPage( SIdxKeyTable *pIdx );
DWORD ComputeLoad( SIdxKeyTable *pKT );
DWORD InsertPhase2( SIdxKeyTable *pCurrent, WORD wID, LPSTR pszKey, DWORD dwValue, DWORD Stack[], LONG &StackPtr );
DWORD Search( IN LPSTR pszKey, OUT SIdxKeyTable **pRetIdx, OUT WORD *pwID, DWORD Stack[], LONG &StackPtr );
public: CBTree(); ~CBTree();
DWORD Init(CBTreeFile *pSrc); DWORD Shutdown(DWORD dwShutDownFlags);
DWORD InsertKey( IN LPSTR pszKey, DWORD dwValue );
DWORD FindKey( IN LPSTR pszKey, DWORD *pdwData );
DWORD DeleteKey( IN LPSTR pszKey );
DWORD BeginEnum( LPSTR pszStartKey, OUT CBTreeIterator **pIterator );
void Dump(FILE *fp);
DWORD InvalidateCache();
DWORD FlushCaches(); };
#endif
|