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

285 lines
7.2 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************
* *
* BTDELETE.C *
* *
* Copyright (C) Microsoft Corporation 1989 - 1994. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* *
* Btree deletion functions and helpers. *
* *
******************************************************************************
* *
* Current Owner: Binhn *
* *
*****************************************************************************/
static char s_aszModule[]= __FILE__; /* For error report */
#include <mvopsys.h>
#include <misc.h>
#include <orkin.h>
#include <iterror.h>
#include <wrapstor.h>
#include <_mvutil.h>
/* Put all functions into the same segment to avoid memory fragmentation
* and load time surplus for the MAC
*/
// #pragma code_seg ("MVFS")
/***************************************************************************
*
* Public Functions
*
***************************************************************************/
/***************************************************************************\
*
* @doc PUBLIC API
*
* @func HRESULT PASCAL FAR | RcDeleteHbt |
* delete a key from a btree.
* Just copy over the key and update cbSlack.
* Doesn't yet merge blocks less than half full or update key in
* parent key if we deleted the first key in a block.
*
*
* @parm HBT | hbt |
* handle of the btree
*
* @parm KEY | key |
* the key to delete from the btree
*
* @rdesc S_OK if delete works; ERR_NOTEXIST
*
* @rcomm Unfinished: doesn't do block merges or parent updates.
*
***************************************************************************/
PUBLIC HRESULT PASCAL FAR EXPORT_API RcDeleteHbt(HBT hbt, KEY key)
{
QBTHR qbthr;
HF hf;
HRESULT rc;
QCB qcb;
QB qb;
SHORT cb;
BTPOS btpos;
if ((qbthr = (QBTHR)_GLOBALLOCK(hbt)) == NULL)
return(E_INVALIDARG);
hf = qbthr->hf;
if (qbthr->bth.bFlags & fFSOpenReadOnly)
{
rc = E_NOPERMISSION;
exit0:
_GLOBALUNLOCK(hbt);
return rc;
}
/* look up the key */
if ((rc = RcLookupByKey(hbt, key, &btpos, NULL)) != S_OK)
goto exit0;
qbthr->qCache = _GLOBALLOCK(qbthr->ghCache);
// copy over this key and rec with subsequent keys and recs
if ((qcb = QCacheBlock(qbthr, qbthr->bth.cLevels - 1)) == NULL)
{
rc = E_FAIL;
exit1:
_GLOBALUNLOCK(qbthr->ghCache);
goto exit0;
}
qb = qcb->db.rgbBlock + btpos.iKey;
cb = CbSizeKey((KEY)qb, qbthr, TRUE);
cb += CbSizeRec(qb + cb, qbthr);
QVCOPY(qb, qb + cb, (LONG)(qbthr->bth.cbBlock +
(QB)&(qcb->db) - qb - cb - qcb->db.cbSlack));
qcb->db.cbSlack += cb;
// if this was the first key in the leaf block, update key in parent
// >>>>> code goes here
// if block is now less than half full, merge blocks
// >>>>> code goes here
qcb->db.cKeys--;
qcb->bFlags |= fCacheDirty;
qbthr->bth.lcEntries--;
qbthr->bth.bFlags |= fFSDirty;
rc = S_OK;
goto exit1;
}
/***************************************************************************\
*
* @doc PUBLIC API
*
* @func HRESULT PASCAL FAR | RcTraverseHbt |
* Traverses entire btree, calling a user function at each entry.
* Optionally, the user can cause the current entry to be deleted.
*
* @parm HBT | hbt |
* handle of the btree
*
* @parm TRAVERSE_FUNC | fnCallback |
* Callback of the form DWORD Callback(KEY key, QB rec, DWORD dwUser)
* return TRAVERSE_DONE for normal exit, TRAVERSE_DELETE to delete this
* entry, TRAVERSE_INTERRUPT to interrupt and stop traversing.
*
* @parm DWORD | dwUser |
* User data that gets passed into the callback.
*
* @rdesc S_OK if delete works
* @comm Assumes that RcDeleteHbt does not do block merges. Keys and
* records are limited to 256 bytes in this function
*
***************************************************************************/
typedef DWORD (FAR PASCAL *TRAVERSE_FUNC) (KEY key, QB rec, DWORD dwUser);
PUBLIC HRESULT PASCAL FAR EXPORT_API RcTraverseHbt(HBT hbt, TRAVERSE_FUNC fnCallback, DWORD dwUser)
{
QBTHR qbthr;
HRESULT rc;
BK bk;
QCB qcb;
QB qb;
BTPOS btpos;
BYTE * pKeyData;
BYTE * pRecData;
HRESULT errb;
SHORT cbKey, cbRec;
if ((hbt==NULL) || (!fnCallback))
return E_INVALIDARG;
if ((qbthr = (QBTHR)_GLOBALLOCK(hbt)) == NULL)
return(E_INVALIDARG);
if (qbthr->bth.lcEntries == (LONG)0)
{
rc = E_NOTEXIST;
exit0:
_GLOBALUNLOCK(hbt);
return rc;
}
if ((bk = qbthr->bth.bkFirst) == bkNil)
{
rc = E_ASSERT;
goto exit0;
}
if (qbthr->ghCache == NULL)
{
if ((rc = RcMakeCache(qbthr)) != S_OK)
goto exit0;
}
qbthr->qCache = _GLOBALLOCK(qbthr->ghCache);
if ((qcb = QFromBk(bk, (SHORT)(qbthr->bth.cLevels - 1), qbthr,
&errb)) == NULL)
{
rc = errb;
exit1:
_GLOBALUNLOCK(qbthr->ghCache);
goto exit0;
}
qb = qcb->db.rgbBlock + 2 * sizeof(BK);
pKeyData=qb;
cbKey = CbSizeKey((KEY)qb, qbthr, TRUE);
qb += cbKey;
pRecData=qb;
cbRec = CbSizeRec(qb, qbthr);
btpos.bk = bk;
btpos.iKey = 2 * sizeof(BK);
btpos.cKey = 0;
while (1)
{
DWORD dwRes=(*fnCallback)((KEY)pKeyData,(QB)pRecData,dwUser);
BTPOS btposNew;
HRESULT errMore;
errMore=RcNextPos( hbt, &btpos, &btposNew ); //==ERR_NOTEXIST)
if (dwRes==1) // delete case
{
if (qbthr->bth.bFlags & fFSOpenReadOnly)
{
rc = E_NOPERMISSION;
goto exit1;
}
// delete entry, and keep btposNew up to date during delete
qcb = QFromBk(btpos.bk, (SHORT)(qbthr->bth.cLevels - 1), qbthr,&errb);
//qb = qcb->db.rgbBlock + btpos.iKey;
qb = qcb->db.rgbBlock + btpos.iKey;
QVCOPY(qb, qb + cbKey + cbRec, (LONG)(qbthr->bth.cbBlock +
(QB)&(qcb->db) - qb - (cbKey + cbRec) - qcb->db.cbSlack));
qcb->db.cbSlack += cbKey + cbRec;
qcb->db.cKeys--;
qcb->bFlags |= fCacheDirty;
qbthr->bth.lcEntries--;
qbthr->bth.bFlags |= fFSDirty;
if (btposNew.bk == btpos.bk)
{
btposNew.iKey-=cbKey + cbRec;
btposNew.cKey--;
}
}
else if (dwRes == 2)
{
rc = E_INTERRUPT;
goto exit1;
}
if (errMore==S_OK)
{
btpos=btposNew;
qcb = QFromBk(btpos.bk, (SHORT)(qbthr->bth.cLevels - 1), qbthr,&errb);
qb = qcb->db.rgbBlock + btpos.iKey;
pKeyData=qb;
cbKey = CbSizeKey((KEY)qb, qbthr, TRUE);
qb += cbKey;
pRecData=qb;
cbRec = CbSizeRec(qb, qbthr);
}
else
break;
}
rc=S_OK;
goto exit1;
}
/* EOF */