windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/common/btree/btree.cpp

1002 lines
26 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************
* *
* BTREE.C *
* *
* Copyright (C) Microsoft Corporation 1989 - 1994. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* *
* Btree manager general functions: open, close, etc. *
* *
******************************************************************************
* *
* Current Owner: BinhN *
* *
*****************************************************************************/
/*****************************************************************************
*
* Revision History: Created 02/10/89 by JohnSc
*
* 2/10/89 johnsc created: stub version
* 3/10/89 johnsc use FS files
* 8/21/89 johnsc autodocified
* 11/08/90 JohnSc added a parameter to RcGetBtreeInfo() to get block size
* 11/29/90 RobertBu #ifdef'ed out a dead routine
* 12/14/90 JohnSc added VerifyHbt()
* 3/05/97 erinfox Change errors to HRESULTS
*
*****************************************************************************/
static char s_aszModule[] = __FILE__; /* For error report */
#include <mvopsys.h>
#include <string.h>
#include <orkin.h>
#include <misc.h>
#include <iterror.h>
#include <wrapstor.h>
#include <mvsearch.h>
#include <_mvutil.h>
#include "common.h"
/***************************************************************************
*
- Function: RcMakeCache(qbthr)
-
* Purpose: Allocate a btree cache with one block per level.
*
* ASSUMES
* args IN: qbthr - no cache
*
* PROMISES
* returns: S_OK, or errors
* args OUT: qbthr->ghCache is allocated; qbthr->qCache is NULL
*
***************************************************************************/
HRESULT PASCAL FAR RcMakeCache(QBTHR qbthr)
{
SHORT i;
/* Sanity check */
if (qbthr == NULL)
return (E_INVALIDARG);
/* Allocate the memory */
if (qbthr->bth.cLevels > 0)
{
// would it work to just alloc 0 bytes???
qbthr->ghCache = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
(LONG)qbthr->bth.cLevels * CbCacheBlock(qbthr) );
if (qbthr->ghCache == NULL)
return (E_OUTOFMEMORY);
qbthr->qCache = (QB) _GLOBALLOCK(qbthr->ghCache);
/* Initialize the flags */
for (i = 0; i < qbthr->bth.cLevels; i++)
QCacheBlock(qbthr, i)->bFlags = (BYTE)0;
_GLOBALUNLOCK(qbthr->ghCache);
}
else {
qbthr->ghCache = NULL;
}
qbthr->qCache = NULL;
return (S_OK);
}
/***************************************************************************
*
* Public Routines
*
***************************************************************************/
/***************************************************************************
*
- Function: HbtCreateBtreeSz(sz, qbtp)
-
* Purpose: Create and open a btree.
*
* ASSUMES
* args IN: sz - name of the btree
* qbtp - pointer to btree params: NO default because we
* need an HFS.
* The bFlags param contains HFILE_SYSTEM for the
* system btree, but none of the btree code should
* care whether or not it is a system file.
*
* PROMISES
* returns: handle to the new btree
*
* Note: KT supported: KT_SZ, KT_LONG, KT_SZI, KT_SZISCAND.
* +++
*
* Method: Btrees are files inside a FS. The FS directory is a
* special file in the FS.
*
***************************************************************************/
HBT FAR PASCAL HbtCreateBtreeSz(LPSTR sz,BTREE_PARAMS FAR *qbtp, PHRESULT phr)
{
HF hf;
HBT hbt;
QBTHR qbthr;
/* see if we support key type */
if (qbtp == NULL ||
(
#ifdef FULL_BTREE // {
qbtp->rgchFormat[0] != KT_SZ
&&
qbtp->rgchFormat[0] != KT_VSTI
&&
qbtp->rgchFormat[0] != KT_SZI
&&
qbtp->rgchFormat[0] != KT_SZMAP
&&
qbtp->rgchFormat[0] != KT_SZISCAND
&&
#endif // }
qbtp->rgchFormat[0] != KT_LONG
&&
qbtp->rgchFormat[0] != KT_EXTSORT) )
{
SetErrCode(phr, E_INVALIDARG);
return NULL;
}
/* allocate btree handle struct */
if (( hbt = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
(LONG)sizeof( BTH_RAM) ) ) == NULL ) {
SetErrCode(phr, E_OUTOFMEMORY);
return NULL;
}
qbthr = (QBTHR) _GLOBALLOCK(hbt);
/* initialize bthr struct */
qbtp->rgchFormat[ wMaxFormat ] = '\0';
lstrcpy(qbthr->bth.rgchFormat, qbtp->rgchFormat[0] == '\0'
? rgchBtreeFormatDefault : qbtp->rgchFormat);
switch (qbtp->rgchFormat[ 0 ])
{
#ifdef FULL_BTREE // {
case KT_SZ:
qbthr->BkScanInternal = BkScanSzInternal;
qbthr->RcScanLeaf = RcScanSzLeaf;
break;
case KT_VSTI:
qbthr->BkScanInternal = BkScanVstiInternal;
qbthr->RcScanLeaf = RcScanVstiLeaf;
break;
case KT_SZI:
qbthr->BkScanInternal = BkScanSziInternal;
qbthr->RcScanLeaf = RcScanSziLeaf;
break;
case KT_SZISCAND:
qbthr->BkScanInternal = BkScanSziScandInternal;
qbthr->RcScanLeaf = RcScanSziScandLeaf;
break;
case KT_SZMAP:
qbthr->BkScanInternal = BkScanCMapInternal ;
qbthr->RcScanLeaf = RcScanCMapLeaf;
break;
#endif // }
case KT_LONG:
qbthr->BkScanInternal = BkScanLInternal;
qbthr->RcScanLeaf = RcScanLLeaf;
break;
case KT_EXTSORT:
qbthr->BkScanInternal = BkScanExtSortInternal ;
qbthr->RcScanLeaf = RcScanExtSortLeaf;
break;
default:
/* unsupported KT */
SetErrCode(phr, E_INVALIDARG);
goto error_return;
break;
}
/* create the btree file */
if (!FHfValid(hf = HfCreateFileHfs(qbtp->hfs, sz, qbtp->bFlags, phr)))
{
goto error_return;
}
qbthr->bth.wMagic = wBtreeMagic;
qbthr->bth.bVersion = bBtreeVersion;
qbthr->bth.bFlags = qbtp->bFlags | fFSDirty;
qbthr->bth.cbBlock = qbtp->cbBlock ? qbtp->cbBlock : cbBtreeBlockDefault;
qbthr->bth.bkFirst =
qbthr->bth.bkLast =
qbthr->bth.bkRoot =
qbthr->bth.bkFree = bkNil;
qbthr->bth.bkEOF = (BK)0;
qbthr->bth.cLevels = 0;
qbthr->bth.lcEntries = (LONG)0;
qbthr->bth.dwCodePageID = qbtp->dwCodePageID;
qbthr->bth.lcid = qbtp->lcid;
qbthr->bth.dwExtSortInstID = qbtp->dwExtSortInstID;
qbthr->bth.dwExtSortKeyType = qbtp->dwExtSortKeyType;
qbthr->hf = hf;
qbthr->cbRecordSize = 0;
qbthr->ghCache = NULL;
qbthr->qCache = NULL;
qbthr->lrglpCharTab = NULL;
qbthr->pITSortKey = NULL;
LcbWriteHf(qbthr->hf, &(qbthr->bth), (LONG)sizeof(BTH), phr ); /* why??? */
_GLOBALUNLOCK(hbt);
return hbt;
error_return:
_GLOBALUNLOCK(hbt);
_GLOBALFREE(hbt);
return NULL;
}
/***************************************************************************
*
- Function: RcDestroyBtreeSz(sz, hfs)
-
* Purpose: destroy an existing btree
*
* Method: look for file and unlink it
*
* ASSUMES
* args IN: sz - name of btree file
* hfs - file system btree lives in
* state IN: btree is closed (if not data will be lost)
*
* PROMISES
* returns: S_OK or errors
*
* Notes: FS directory btree never gets destroyed: you just get rid
* of the whole fs.
*
***************************************************************************/
HRESULT FAR PASCAL RcDestroyBtreeSz(LPSTR sz, HFS hfs)
{
return (RcUnlinkFileHfs(hfs, sz));
}
/***************************************************************************
*
* Function: HbtOpenBtreeSz(sz, hfs, bFlags)
*
* Purpose: open an existing btree
*
* ASSUMES
* args IN: sz - name of the btree (ignored if isdir is set)
* hfs - hfs btree lives in
* bFlags - open mode, isdir flag
* args OUT:
* phr - error code
*
* PROMISES
* returns: handle to the open btree or NULL on failure
* isdir flag set in qbthr->bth.bFlags if indicated
*
***************************************************************************/
HBT FAR PASCAL HbtOpenBtreeSz(LPWSTR sz, HFS hfs, BYTE bFlags, PHRESULT phr)
{
HF hf;
QBTHR qbthr;
HBT hbt;
LONG lcb;
HRESULT rc;
/* allocate struct */
if ((hbt = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
(LONG)sizeof(BTH_RAM))) == NULL)
{
SetErrCode(phr, E_OUTOFMEMORY);
return NULL;
}
qbthr = (QBTHR) _GLOBALLOCK(hbt);
/* open btree file */
if (!FHfValid(hf = HfOpenHfs(hfs, sz, bFlags, phr)))
{
exit0:
_GLOBALUNLOCK (hbt);
_GLOBALFREE(hbt);
return 0;
}
/* read header from file */
lcb = LcbReadHf(hf, &(qbthr->bth), (LONG)sizeof( BTH), phr);
/* MAC swapping stuffs */
if (qbthr->bth.wMagic == SWAPWORD(wBtreeMagic))
{
qbthr->bth.wMagic = SWAPWORD(qbthr->bth.wMagic);
qbthr->bth.cbBlock = SWAPWORD(qbthr->bth.cbBlock);
qbthr->bth.bkFirst = SWAPLONG(qbthr->bth.bkFirst);
qbthr->bth.bkLast = SWAPLONG(qbthr->bth.bkLast);
qbthr->bth.bkRoot = SWAPLONG(qbthr->bth.bkRoot);
qbthr->bth.bkFree = SWAPLONG(qbthr->bth.bkFree);
qbthr->bth.bkEOF = SWAPLONG(qbthr->bth.bkEOF);
qbthr->bth.cLevels = SWAPWORD(qbthr->bth.cLevels);
qbthr->bth.lcEntries = SWAPLONG(qbthr->bth.lcEntries);
qbthr->bth.dwCodePageID = SWAPLONG(qbthr->bth.dwCodePageID);
qbthr->bth.lcid = SWAPLONG(qbthr->bth.lcid);
qbthr->bth.dwExtSortInstID = SWAPLONG(qbthr->bth.dwExtSortInstID);
qbthr->bth.dwExtSortKeyType = SWAPLONG(qbthr->bth.dwExtSortKeyType);
}
if (lcb != (LONG)sizeof(BTH))
{
exit1:
RcCloseHf(hf);
goto exit0;
}
if (qbthr->bth.wMagic != wBtreeMagic)
{
// check magic number
SetErrCode(phr, E_FILEINVALID);
goto exit1;
}
if (qbthr->bth.bVersion != bBtreeVersion)
{
// support >1 vers someday
SetErrCode(phr, E_BADVERSION);
goto exit1;
}
/* initialize stuff */
if ((rc = RcMakeCache(qbthr)) != S_OK)
{
SetErrCode (phr, rc);
goto exit1;
}
qbthr->hf = hf;
qbthr->cbRecordSize = 0;
switch (qbthr->bth.rgchFormat[0])
{
#ifdef FULL_BTREE // {
case KT_SZ:
qbthr->BkScanInternal = BkScanSzInternal;
qbthr->RcScanLeaf = RcScanSzLeaf;
break;
case KT_SZI:
qbthr->BkScanInternal = BkScanSziInternal;
qbthr->RcScanLeaf = RcScanSziLeaf;
break;
case KT_VSTI:
qbthr->BkScanInternal = BkScanVstiInternal;
qbthr->RcScanLeaf = RcScanVstiLeaf;
break;
case KT_SZISCAND:
qbthr->BkScanInternal = BkScanSziScandInternal;
qbthr->RcScanLeaf = RcScanSziScandLeaf;
break;
case KT_SZMAP:
qbthr->BkScanInternal = BkScanCMapInternal ;
qbthr->RcScanLeaf = RcScanCMapLeaf;
break;
#endif // }
case KT_LONG:
qbthr->BkScanInternal = BkScanLInternal;
qbthr->RcScanLeaf = RcScanLLeaf;
break;
case KT_EXTSORT:
qbthr->BkScanInternal = BkScanExtSortInternal ;
qbthr->RcScanLeaf = RcScanExtSortLeaf;
break;
default: // unsupported KT
SetErrCode(phr, E_INVALIDARG);
goto exit1;
break;
}
assert(! ( qbthr->bth.bFlags & ( fFSDirty) ) );
if ((bFlags | qbthr->bth.bFlags) & ( fFSReadOnly | fFSOpenReadOnly ))
{
qbthr->bth.bFlags |= fFSOpenReadOnly;
}
_GLOBALUNLOCK(hbt);
return hbt;
}
/***************************************************************************
*
* Function: GetBtreeParams(hbt, qbtp)
*
* Purpose: open an existing btree
*
* ASSUMES
* args IN: hbt - handle to btree info
* args OUT:
* qbtp - Btree params (key type info, etc.). All members
* of the structure are set EXCEPT for the hfs.
*
* PROMISES
* returns: nothing
*
***************************************************************************/
VOID FAR PASCAL GetBtreeParams(HBT hbt, BTREE_PARAMS FAR *qbtp)
{
if (hbt != NULL && qbtp != NULL)
{
QBTHR qbthr;
qbthr = (QBTHR) _GLOBALLOCK(hbt);
// Copy btree info to BTREE_PARMS.
qbtp->cbBlock = qbthr->bth.cbBlock;
qbtp->dwCodePageID = qbthr->bth.dwCodePageID;
qbtp->lcid = qbthr->bth.lcid;
qbtp->dwExtSortInstID = qbthr->bth.dwExtSortInstID;
qbtp->dwExtSortKeyType = qbthr->bth.dwExtSortKeyType;
qbtp->bFlags = qbthr->bth.bFlags;
lstrcpy(qbtp->rgchFormat, qbthr->bth.rgchFormat);
_GLOBALUNLOCK(hbt);
}
else
{
ITASSERT(FALSE);
}
}
/***************************************************************************
*
- Function: RcCloseOrFlushHbt(hbt, fClose)
-
* Purpose: Close or flush the btree. Flush only works for directory
* btree. (Is this true? If so, why?)
*
* ASSUMES
* args IN: hbt
* fClose - TRUE to close the btree, FALSE to flush it
*
* PROMISES
* returns: rc
* args OUT: hbt - the btree is still open and cache still exists
*
* NOTE: This function gets called by RcCloseOrFlushHfs() even if
* there was an error (just to clean up memory.)
*
***************************************************************************/
HRESULT FAR PASCAL RcCloseOrFlushHbt(HBT hbt, BOOL fClose)
{
QBTHR qbthr;
HF hf;
int fRet;
HANDLE hnd;
HRESULT errb;
if (hbt == 0)
return (E_INVALIDARG);
qbthr = (QBTHR) _GLOBALLOCK(hbt);
fRet = S_OK;
hf = qbthr->hf;
if (qbthr->ghCache != NULL)
{
qbthr->qCache = (QB) _GLOBALLOCK(qbthr->ghCache);
}
fRet = S_OK;
if (qbthr->bth.bFlags & fFSDirty)
{
assert(!( qbthr->bth.bFlags & ( fFSReadOnly | fFSOpenReadOnly) ) );
if (qbthr->ghCache != NULL &&
(fRet = RcFlushCache(qbthr)) != S_OK)
{
exit0:
/* Close/flush the B-tree */
// Previously
//if ((fRet = RcCloseOrFlushHf(hf, fClose,
// qbthr->bth.bFlags & fFSOptCdRom ? sizeof(BTH):0))!= S_OK)
if (fClose)
fRet=RcCloseHf(hf);
else
fRet=RcFlushHf(hf);
if ((fRet!=S_OK) || (fClose))
/* Release the memory */
{ if ((hnd = qbthr->ghCache) != NULL)
{
while ((GlobalFlags(hnd) & GMEM_LOCKCOUNT) > 0)
_GLOBALUNLOCK(hnd);
if (fClose)
{
_GLOBALFREE(hnd);
qbthr->ghCache = 0;
}
}
}
else
{
if (qbthr->ghCache)
{ _GLOBALUNLOCK(qbthr->ghCache);
qbthr->qCache=NULL;
}
}
// Before we free the BTHR, we need to release any sort object we're
// holding onto.
if (fClose && qbthr->pITSortKey != NULL)
{
qbthr->pITSortKey->Release();
qbthr->pITSortKey = NULL;
}
_GLOBALUNLOCK(hbt);
if (fClose)
_GLOBALFREE(hbt);
return fRet;
}
qbthr->bth.bFlags &= ~(fFSDirty);
if (!FoEquals(FoSeekHf(hf, foNil, wFSSeekSet, &errb),foNil))
goto exit0;
LcbWriteHf(hf, &(qbthr->bth), (LONG)sizeof(BTH), &errb);
}
goto exit0;
}
/***************************************************************************
*
- Function: RcCloseBtreeHbt(hbt)
-
* Purpose: Close an open btree. If it's been modified, save changes.
*
* ASSUMES
* args IN: hbt
*
* PROMISES
* returns: S_OK or error
*
***************************************************************************/
HRESULT FAR PASCAL RcCloseBtreeHbt(HBT hbt)
{
return RcCloseOrFlushHbt(hbt, TRUE);
}
#ifdef DEADROUTINE
/***************************************************************************
*
- Function: RcFlushHbt(hbt)
-
* Purpose: Write any btree changes to disk.
* Btree stays open, cache remains.
*
* ASSUMES
* args IN: hbt
*
* PROMISES
* returns: rc
*
***************************************************************************/
HRESULT FAR PASCAL RcFlushHbt(HBT hbt)
{
return RcCloseOrFlushHbt(hbt, FALSE);
}
#endif
/***************************************************************************
*
- Function: HRESULT RcFreeCacheHbt(hbt)
-
* Purpose: Free the btree cache.
*
* ASSUMES
* args IN: hbt - ghCache is NULL or allocated; qCache not locked
*
* PROMISES
* returns: S_OK or errors
* args OUT: hbt - ghCache is NULL; qCache is NULL
*
***************************************************************************/
HRESULT FAR PASCAL RcFreeCacheHbt(HBT hbt)
{
QBTHR qbthr;
HRESULT rc = S_OK;
if (hbt == NULL)
{
return E_INVALIDARG;
}
qbthr = (QBTHR) _GLOBALLOCK(hbt);
if (qbthr->ghCache != NULL) {
qbthr->qCache = (QB) _GLOBALLOCK(qbthr->ghCache);
rc = RcFlushCache(qbthr);
_GLOBALUNLOCK(qbthr->ghCache);
_GLOBALFREE(qbthr->ghCache);
qbthr->ghCache = NULL;
qbthr->qCache = NULL;
}
_GLOBALUNLOCK(hbt);
return rc;
}
/***************************************************************************
*
- Function: RcGetBtreeInfo(hbt, qchFormat, qlcKeys)
-
* Purpose: Return btree info: format string and/or number of keys
*
* ASSUMES
* args IN: hbt
* qchFormat - pointer to buffer for fmt string or NULL
* qlcKeys - pointer to long for key count or NULL
* qcbBlock - pointer to int for block size in bytes or NULL
*
* PROMISES
* returns: rc
* args OUT: qchFormat - btree format string copied here
* qlcKeys - gets number of keys in btree
* qcbBlock - gets number of bytes in a block
*
***************************************************************************/
HRESULT FAR PASCAL RcGetBtreeInfo(HBT hbt, LPBYTE qchFormat,
QL qlcKeys, QW qcbBlock)
{
QBTHR qbthr;
if ((qbthr = (QBTHR) _GLOBALLOCK(hbt)) == NULL)
return(E_INVALIDARG);
if (qchFormat != NULL)
STRCPY ((char *) qchFormat, qbthr->bth.rgchFormat);
if (qlcKeys != NULL)
*(LPUL)qlcKeys = qbthr->bth.lcEntries;
if (qcbBlock != NULL)
*qcbBlock = qbthr->bth.cbBlock;
_GLOBALUNLOCK(hbt);
return S_OK;
}
/***************************************************************************
*
- Function: RcAbandonHbt(hbt)
-
* Purpose: Abandon an open btree. All changes since btree was opened
* will be lost. If btree was opened with a create, it is
* as if the create never happened.
*
* ASSUMES
* args IN: hbt
*
* PROMISES
* returns: rc
* +++
*
* Method: Just abandon the file and free memory.
*
***************************************************************************/
PUBLIC HRESULT PASCAL FAR EXPORT_API RcAbandonHbt(HBT hbt)
{
QBTHR qbthr;
int fRet;
/* Sanity check */
if ((qbthr = (QBTHR) _GLOBALLOCK(hbt)) == NULL)
return(E_INVALIDARG);
if (qbthr->ghCache != NULL)
_GLOBALFREE(qbthr->ghCache);
fRet = RcAbandonHf(qbthr->hf);
_GLOBALUNLOCK(hbt);
_GLOBALFREE(hbt);
return fRet;
}
#if 0
/*************************************************************************
* @doc API
*
* @func PASCAL FAR | DiskBtreeCreate |
* Given a pointer to the B-tree ofthe file system, the fucntion
* will copy it to a disk file.
*
* @parm QBTHR | qbt |
* Pointer to the B-tree structure
*
* @parm LPSTR | szFilename |
* Disk filename
*
* @rdesc S_OK if succeeded, else various Rc errors
*
* @comm The current assumption is that the whole B-tree is less
* 64K. It is assume that the whole structure will reside
* in memory at runtime.
*************************************************************************/
HRESULT EXPORT_API PASCAL FAR DiskBtreeCreate (QBTHR qbt, LPSTR szFilename)
{
#ifdef MOSMAP // {
// Disable function
return ERR_FAILED;
#else // } {
DWORD dwbtSize; /* Total size of B-tree */
WORD wBlockSize; /* Size of a B-tree block */
int fRet; /* Return error value */
HANDLE hbtBuf; /* Handle to B-tree memory buffer */
QB qbtBuf; /* pointer to B-tree memory buffer */
int hFile; /* temp file handle */
/* Calculate the size of the B-tree buffer */
wBlockSize = qbt->bth.cbBlock;
dwbtSize = qbt->bth.bkEOF * wBlockSize;
if (dwbtSize >= 0xffff)
return ERR_FAILED;
/* Allocate a buffer to hold the data */
if ((hbtBuf = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE | GMEM_MOVEABLE, dwbtSize)) == NULL) {
return E_OUTOFMEMORY;
}
qbtBuf = (QB)_GLOBALLOCK (hbtBuf);
/* We can read everything at once into memory. First seek to the
* correct position
*/
if (DwSeekHf(qbt->hf, (LONG)sizeof(BTH), wFSSeekSet) != sizeof(BTH)) {
fRet = ERR_SEEK_FAILED;
exit0:
_GLOBALUNLOCK (hbtBuf);
_GLOBALFREE (hbtBuf);
return fRet;
}
/* Read in the whole B-tree */
if (LcbReadHf(qbt->hf, qbtBuf, dwbtSize) != (LONG)dwbtSize) {
fRet = ERR_FAILED;
goto exit0;
}
/* Open the disk file */
if ((hFile = _lcreat (szFilename, 0)) == HFILE_ERROR) {
fRet = ERR_FILECREAT_FAILED;
goto exit0;
}
/* Write the B-tree file header. Set bFlags = !fCompressed */
qbt->bth.bFlags = 0;
if ((_lwrite (hFile, (QB)&qbt->bth, sizeof(BTH))) != sizeof(BTH)) {
fRet = ERR_CANTWRITE;
exit1:
_lclose (hFile);
goto exit0;
}
/* Write the whole B-tree */
if ((_lwrite (hFile, qbtBuf, (WORD)dwbtSize)) != (WORD)dwbtSize) {
fRet = ERR_CANTWRITE;
goto exit1;
}
fRet = S_OK;
goto exit0;
#endif //}
}
/*************************************************************************
* @doc API
*
* @func HBT PASCAL FAR | DiskBtreeLoad |
* :Load a B-tree structure saved on disk into memroy
*
* @parm LPSTR | szFilename |
* Disk filename
*
* @rdesc The function returns a handle to the B-tree in memory
* if succeeded, 0 otherwise
*
* @comm The current assumption is that the whole B-tree is less
* 64K. It is assume that the whole structure will reside
* in memory at runtime.
*************************************************************************/
HBT EXPORT_API PASCAL FAR DiskBtreeLoad (LPSTR szFilename)
{
int hFile; /* File handle */
BTH btHeader; /* B-tree header */
HANDLE hbt = 0; /* Handle to B-tree structure */
DWORD dwbtSize; /* Size of B-tree */
QBTHR qbt; /* Pointer to B-tree structure */
HRESULT fRet; /* Error return code */
/* Open the file */
if ((hFile = _lopen ((QB)szFilename, OF_READ)) == HFILE_ERROR) {
SetErrCode (ERR_NOTEXIST);
return NULL;
}
/* Read in the header */
if ((_lread (hFile, (QB)&btHeader, sizeof (BTH))) != sizeof (BTH)) {
fRet = ERR_CANTREAD;
exit0:
SetErrCode (fRet);
_lclose (hFile);
return hbt;
}
/* MAC swapping stuffs */
btHeader.wMagic = SWAPWORD(btHeader.wMagic);
btHeader.cbBlock = SWAPWORD(btHeader.cbBlock);
btHeader.bkFirst = SWAPLONG(btHeader.bkFirst);
btHeader.bkLast = SWAPLONG(btHeader.bkLast);
btHeader.bkRoot = SWAPLONG(btHeader.bkRoot);
btHeader.bkFree = SWAPLONG(btHeader.bkFree);
btHeader.bkEOF = SWAPLONG(btHeader.bkEOF);
btHeader.lcEntries = SWAPLONG(btHeader.lcEntries);
btHeader.dwCodePageID = SWAPLONG(btHeader.dwCodePageID);
btHeader.lcid = SWAPLONG(btHeader.lcid);
btHeader.dwExtSortInstID = SWAPLONG(btHeader.dwExtSortInstID);
btHeader.dwExtSortKeyType = SWAPLONG(btHeader.dwExtSortKeyType);
/* Check for validity */
if (btHeader.wMagic != wBtreeMagic) { // check magic number
fRet = ERR_INVALID;
goto exit0;
}
if (btHeader.bVersion != bBtreeVersion) {// Check version
fRet = E_BADVERSION;
goto exit0;
}
dwbtSize = btHeader.bkEOF * btHeader.cbBlock;
/* Currently we do not support a B-tree larger than 64K */
if (dwbtSize >= 0xffff) {
fRet = ERR_NOTSUPPORTED;
goto exit0;
}
/* Allocate the block of memory for the B-tree */
if ((hbt = _GLOBALALLOC (GMEM_ZEROINIT | GMEM_SHARE | GMEM_MOVEABLE, sizeof (BTH_RAM) + dwbtSize)) == NULL) {
fRet = E_OUTOFMEMORY;
goto exit0;
}
qbt = (QBTHR)_GLOBALLOCK (hbt);
/* Initialize the structure */
qbt->bth = btHeader;
qbt->ghCache = hbt;
qbt->qCache = (QB)qbt + sizeof (BTH_RAM);
/* Read in the B-tree */
if ((_lread (hFile, qbt->qCache, (WORD)dwbtSize)) != dwbtSize) {
fRet = ERR_CANTREAD;
_GLOBALUNLOCK (hbt);
_GLOBALFREE (hbt);
hbt = 0;
goto exit0;
}
_GLOBALUNLOCK (hbt);
fRet = S_OK;
goto exit0;
}
/*************************************************************************
* @doc API
*
* @func VOID PASCAL FAR | DiskBtreeFree |
* Free the in-memroy B-tree
*
* @parm HBT | hbt |
* Handle to the B-tree structure
*
*************************************************************************/
VOID EXPORT_API PASCAL FAR DiskBtreeFree (HBT hbt)
{
if (hbt) {
_GLOBALUNLOCK (hbt);
_GLOBALFREE (hbt);
}
}
#endif // if 0
#ifdef _DEBUG
/***************************************************************************
*
- Function: VerifyHbt(hbt)
-
* Purpose: Verify the consistency of an HBT. The main criterion
* is whether an RcAbandonHbt() would succeed.
*
* ASSUMES
* args IN: hbt
*
* PROMISES
* state OUT: Asserts on failure.
*
* Note: hbt == NULL is considered OK.
* +++
*
* Method: Check the qfshr and cache memory. Check the HF.
*
***************************************************************************/
PUBLIC VOID PASCAL FAR EXPORT_API VerifyHbt(HBT hbt)
{
QBTHR qbthr;
if (hbt == NULL) return;
qbthr = (QBTHR) _GLOBALLOCK(hbt);
assert(qbthr != NULL);
VerifyHf(qbthr->hf);
_GLOBALUNLOCK(hbt);
}
#endif // _DEBUG
/* EOF */