//*************************************************************************** // // (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 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