Files
mars-flaim/xflaim/src/flsweep.cpp
ahodgkinson 0ffef299a0 XFLAIM modifications to use FTK.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@383 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-05-08 22:35:48 +00:00

1163 lines
23 KiB
C++

//------------------------------------------------------------------------------
// Desc: Contains the code to F_Db::sweep method
//
// Tabs: 3
//
// Copyright (c) 1996-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: flsweep.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC ELM_ATTR_STATE_INFO * sweepFindState(
ELM_ATTR_STATE_INFO * pStateTbl,
FLMUINT uiNumItems,
FLMUINT uiDictType,
FLMUINT uiDictNum,
FLMUINT * puiTblSlot);
/****************************************************************************
Desc: Provides the ability to scan a FLAIM database to delete or check
for usage of elements and attributes.
****************************************************************************/
RCODE F_Db::sweep(
IF_Thread * pThread)
{
RCODE rc = NE_XFLM_OK;
FLMBOOL bStartedTrans = FALSE;
ELM_ATTR_STATE_INFO * pStateTbl = NULL;
FLMUINT uiNumItems = 0;
F_COLLECTION * pCollection;
FLMUINT uiCollection;
F_Btree * pbtree = NULL;
FLMBYTE ucKey [FLM_MAX_NUM_BUF_SIZE];
FLMUINT uiKeyLen = 0;
FLMUINT64 ui64NodeId;
FLMBOOL bNeg;
FLMUINT uiBytesProcessed;
FLMUINT64 ui64SavedTransId;
F_DOMNode * pNode = NULL;
eDomNodeType eNodeType;
// See if the database is being forced to close
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
{
goto Exit;
}
// Must not be a transaction going.
if (m_eTransType != XFLM_NO_TRANS)
{
rc = RC_SET( NE_XFLM_TRANS_ACTIVE);
goto Exit;
}
// Start a read transaction
if (RC_BAD( rc = beginTrans( XFLM_READ_TRANS,
XFLM_NO_TIMEOUT, XFLM_DONT_POISON_CACHE)))
{
goto Exit;
}
bStartedTrans = TRUE;
// Determine which elements and attributes have been marked for
// purging or checking.
if (RC_BAD( rc = sweepGatherList( &pStateTbl, &uiNumItems)))
{
goto Exit;
}
// If there were no items to check or purge, we are done
if (!uiNumItems)
{
goto Exit; // Will return NE_XFLM_OK
}
// Walk through every node in the database.
uiCollection = 0;
pCollection = NULL;
for (;;)
{
if( pThread->getShutdownFlag())
{
goto Exit;
}
// Get the next collection if necessary.
if (!pCollection)
{
pCollection = m_pDict->getNextCollection( uiCollection, TRUE);
if (!pCollection)
{
break;
}
uiCollection = pCollection->lfInfo.uiLfNum;
if (pbtree)
{
pbtree->btClose();
}
else
{
// Get a btree
if (RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pbtree)))
{
goto Exit;
}
}
if (RC_BAD( rc = pbtree->btOpen( this, &pCollection->lfInfo,
FALSE, TRUE)))
{
goto Exit;
}
uiKeyLen = sizeof( ucKey);
if (RC_BAD( rc = flmNumber64ToStorage( 1, &uiKeyLen,
ucKey, FALSE, TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = pbtree->btLocateEntry(
ucKey, sizeof( ucKey), &uiKeyLen, XFLM_INCL)))
{
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = NE_XFLM_OK;
// Go to the next collection, if any.
pCollection = NULL;
continue;
}
goto Exit;
}
}
// Get the node ID
if (RC_BAD( rc = flmCollation2Number( uiKeyLen, ucKey,
&ui64NodeId, &bNeg, &uiBytesProcessed)))
{
goto Exit;
}
if (RC_BAD( rc = getNode( uiCollection, ui64NodeId, &pNode)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
// Better be able to find the node at this point!
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
ui64SavedTransId = getTransID();
eNodeType = pNode->getNodeType();
if( eNodeType == ELEMENT_NODE)
{
if( RC_BAD( rc = sweepCheckElementState( pNode,
pStateTbl, &uiNumItems, &bStartedTrans)))
{
goto Exit;
}
}
if( !uiNumItems)
{
goto Exit;
}
// If the transaction changed, it was due to a dictionary update.
// Need to refresh the b-tree because it is using an out-of-date
// lfile.
if( getTransID() != ui64SavedTransId)
{
if( RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
{
if( rc == NE_XFLM_BAD_COLLECTION)
{
rc = NE_XFLM_OK;
// Go to the next collection, if any.
pCollection = NULL;
continue;
}
goto Exit;
}
pbtree->btClose();
if( RC_BAD( rc = pbtree->btOpen( this, &pCollection->lfInfo,
FALSE, TRUE)))
{
goto Exit;
}
if( RC_BAD( rc = pbtree->btLocateEntry( ucKey, sizeof( ucKey),
&uiKeyLen, XFLM_EXCL)))
{
if (rc == NE_XFLM_EOF_HIT || rc == NE_XFLM_NOT_FOUND)
{
rc = NE_XFLM_OK;
pCollection = NULL;
continue;
}
goto Exit;
}
}
else
{
if (RC_BAD( rc = pbtree->btNextEntry( ucKey,
sizeof( ucKey), &uiKeyLen)))
{
if( rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
pCollection = NULL;
continue;
}
goto Exit;
}
}
}
// Now go through all of the items we gathered at the beginning and
// if they are still in the state we first looked at them, remove
// them.
if( RC_BAD( rc = sweepFinalizeStates( pStateTbl, uiNumItems,
&bStartedTrans)))
{
goto Exit;
}
Exit:
if( bStartedTrans)
{
(void)abortTrans();
}
if( pNode)
{
pNode->Release();
}
if( pStateTbl)
{
f_free( &pStateTbl);
}
if( pbtree)
{
gv_XFlmSysData.pBtPool->btpReturnBtree( &pbtree);
}
return( rc);
}
/****************************************************************************
Desc: Gather the list of elements and attributes that are marked as
needed to be checked or purged. This routine assumes that a read
transaction is already going.
****************************************************************************/
RCODE F_Db::sweepGatherList(
ELM_ATTR_STATE_INFO ** ppStateTbl,
FLMUINT * puiNumItems)
{
RCODE rc = NE_XFLM_OK;
FLMUINT uiDictType;
FLMUINT uiDictNum;
FLMUINT uiStateTblSize = 0;
ELM_ATTR_STATE_INFO * pStateInfo;
F_DOMNode * pDictDoc = NULL;
F_AttrElmInfo defInfo;
flmAssert( *puiNumItems == 0);
flmAssert( *ppStateTbl == NULL);
// Gather the elements and attributes that have been marked for
// purging or checking.
uiDictType = ELM_ELEMENT_TAG;
uiDictNum = 0;
for (;;)
{
if (uiDictType == ELM_ELEMENT_TAG)
{
if (RC_BAD( rc = m_pDict->getNextElement( this, &uiDictNum,
&defInfo)))
{
if (rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
uiDictNum = 0;
uiDictType = ELM_ATTRIBUTE_TAG;
continue;
}
goto Exit;
}
}
else
{
if (RC_BAD( rc = m_pDict->getNextAttribute( this, &uiDictNum,
&defInfo)))
{
if (rc == NE_XFLM_EOF_HIT)
{
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
}
if (defInfo.m_uiState == ATTR_ELM_STATE_CHECKING ||
defInfo.m_uiState == ATTR_ELM_STATE_PURGE)
{
// Add to the state table, increase table size if needed.
if (*puiNumItems == uiStateTblSize)
{
ELM_ATTR_STATE_INFO * pNewTbl;
FLMUINT uiNewSize;
// Increase by 100 at a time - should be plenty, because
// applications are not going to be checking 100s of
// elements or attributes at a time.
uiNewSize = uiStateTblSize + 100;
if (RC_BAD( rc = f_calloc( uiNewSize *
sizeof( ELM_ATTR_STATE_INFO),
&pNewTbl)))
{
goto Exit;
}
if (uiStateTblSize)
{
f_memcpy( pNewTbl, *ppStateTbl,
sizeof( ELM_ATTR_STATE_INFO) * uiStateTblSize);
f_free( ppStateTbl);
}
*ppStateTbl = pNewTbl;
uiStateTblSize = uiNewSize;
}
pStateInfo = &((*ppStateTbl)[*puiNumItems]);
pStateInfo->uiDictType = uiDictType;
pStateInfo->uiDictNum = uiDictNum;
pStateInfo->uiState = defInfo.m_uiState;
// Read the dictionary item and get its state change count.
if (RC_BAD( rc = getDictionaryDef( uiDictType, uiDictNum,
(IF_DOMNode **)&pDictDoc)))
{
goto Exit;
}
if (RC_BAD( rc = pDictDoc->getAttributeValueUINT64( this,
ATTR_STATE_CHANGE_COUNT_TAG,
&pStateInfo->ui64StateChangeCount)))
{
goto Exit;
}
(*puiNumItems)++;
}
defInfo.resetInfo();
}
Exit:
if (pDictDoc)
{
pDictDoc->Release();
}
return( rc);
}
/****************************************************************************
Desc: Find an element or attribute's state.
****************************************************************************/
FSTATIC ELM_ATTR_STATE_INFO * sweepFindState(
ELM_ATTR_STATE_INFO * pStateTbl,
FLMUINT uiNumItems,
FLMUINT uiDictType,
FLMUINT uiDictNum,
FLMUINT * puiTblSlot
)
{
ELM_ATTR_STATE_INFO * pStateInfo = NULL;
FLMUINT uiTblSize;
FLMUINT uiLow;
FLMUINT uiMid;
FLMUINT uiHigh;
FLMUINT uiTblDictType;
FLMUINT uiTblDictNum;
FLMINT iCmp;
// Do binary search in the table
if ((uiTblSize = uiNumItems) == 0)
{
goto Exit;
}
uiHigh = --uiTblSize;
uiLow = 0;
for (;;)
{
uiMid = (uiLow + uiHigh) / 2;
uiTblDictType = pStateTbl [uiMid].uiDictType;
uiTblDictNum = pStateTbl [uiMid].uiDictNum;
if (uiDictType == uiTblDictType)
{
if (uiDictNum == uiTblDictNum)
{
// Found Match
pStateInfo = &pStateTbl [uiMid];
*puiTblSlot = uiMid;
goto Exit;
}
else if (uiDictNum < uiTblDictNum)
{
iCmp = -1;
}
else
{
iCmp = 1;
}
}
else if (uiDictType < uiTblDictType)
{
iCmp = -1;
}
else
{
iCmp = 1;
}
// Check if we are done
if (uiLow >= uiHigh)
{
// Done, item not found
goto Exit;
}
if (iCmp < 0)
{
if (uiMid == 0)
{
goto Exit;
}
uiHigh = uiMid - 1;
}
else
{
if (uiMid == uiTblSize)
{
goto Exit;
}
uiLow = uiMid + 1;
}
}
Exit:
return( pStateInfo);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_Db::sweepCheckElementState(
F_DOMNode * pElementNode,
ELM_ATTR_STATE_INFO * pStateTbl,
FLMUINT * puiNumItems,
FLMBOOL * pbStartedTrans)
{
RCODE rc = NE_XFLM_OK;
ELM_ATTR_STATE_INFO * pStateInfo;
FLMUINT uiNameId;
FLMUINT uiTblSlot;
F_DOMNode * pDictDoc = NULL;
FLMUINT64 ui64StateChangeCount;
F_AttrElmInfo defInfo;
if( RC_BAD( rc = pElementNode->getNameId( this, &uiNameId)))
{
goto Exit;
}
if( !uiNameId)
{
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
goto Exit;
}
pStateInfo = sweepFindState( pStateTbl, *puiNumItems,
ELM_ELEMENT_TAG, uiNameId, &uiTblSlot);
if( pStateInfo)
{
// Stop the read transaction and start an update
// transaction.
if( RC_BAD( rc = abortTrans()))
{
goto Exit;
}
*pbStartedTrans = FALSE;
if( RC_BAD( rc = beginTrans( XFLM_UPDATE_TRANS)))
{
goto Exit;
}
*pbStartedTrans = TRUE;
// Get the current state to see if it has changed.
if( RC_BAD( rc = m_pDict->getElement( this, uiNameId, &defInfo)))
{
if( rc != NE_XFLM_BAD_ELEMENT_NUM)
{
goto Exit;
}
rc = NE_XFLM_OK;
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
// Read the dictionary item and get its state change count.
if( RC_BAD( rc = getDictionaryDef( ELM_ELEMENT_TAG, uiNameId,
(IF_DOMNode **)&pDictDoc)))
{
goto Exit;
}
if( RC_BAD( rc = pDictDoc->getAttributeValueUINT64( this,
ATTR_STATE_CHANGE_COUNT_TAG, &ui64StateChangeCount)))
{
goto Exit;
}
if( ui64StateChangeCount != pStateInfo->ui64StateChangeCount)
{
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
// If the item's state is still 'checking' set it to
// active.
if( pStateInfo->uiState == ATTR_ELM_STATE_CHECKING)
{
if( defInfo.m_uiState == ATTR_ELM_STATE_CHECKING)
{
if( RC_BAD( rc = changeItemState( ELM_ELEMENT_TAG, uiNameId,
XFLM_ACTIVE_OPTION_STR)))
{
goto Exit;
}
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
}
else
{
// If the state is not still purge, don't do anything more
// on this element - set state to active, so no more purges
// will take place.
if( defInfo.m_uiState != ATTR_ELM_STATE_PURGE)
{
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
else
{
if( RC_BAD( rc = pElementNode->deleteNode( this)))
{
if( rc != NE_XFLM_DOM_NODE_DELETED)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
pElementNode = NULL;
}
}
// Commit the transaction
*pbStartedTrans = FALSE;
if( RC_BAD( rc = commitTrans( 0, FALSE)))
{
goto Exit;
}
// If the state got changed to active, remove the thing from the
// array and decrement the item count. It means we have stopped
// processing this item.
if( pStateInfo->uiState != defInfo.m_uiState)
{
if( uiTblSlot < *puiNumItems - 1)
{
f_memmove( &pStateTbl [uiTblSlot], &pStateTbl [uiTblSlot + 1],
sizeof( ELM_ATTR_STATE_INFO) *
(*puiNumItems - 1 - uiTblSlot));
}
(*puiNumItems)--;
}
// Restart the read transaction.
if( RC_BAD( rc = beginTrans( XFLM_READ_TRANS,
XFLM_NO_TIMEOUT, XFLM_DONT_POISON_CACHE)))
{
goto Exit;
}
*pbStartedTrans = TRUE;
}
// Check the element's attributes
if( pElementNode)
{
if( RC_BAD( rc = sweepCheckAttributeStates( pElementNode,
pStateTbl, puiNumItems, pbStartedTrans)))
{
goto Exit;
}
}
Exit:
if( pDictDoc)
{
pDictDoc->Release();
}
if( RC_BAD( rc) && *pbStartedTrans)
{
abortTrans();
*pbStartedTrans = FALSE;
}
return( rc);
}
/****************************************************************************
Desc:
****************************************************************************/
RCODE F_Db::sweepCheckAttributeStates(
F_DOMNode * pElementNode,
ELM_ATTR_STATE_INFO * pStateTbl,
FLMUINT * puiNumItems,
FLMBOOL * pbStartedTrans)
{
RCODE rc = NE_XFLM_OK;
ELM_ATTR_STATE_INFO * pStateInfo;
FLMUINT uiTblSlot;
FLMUINT uiNameId;
F_DOMNode * pDictDoc = NULL;
IF_DOMNode * pAttrNode = NULL;
IF_DOMNode * pNextAttrNode = NULL;
FLMUINT64 ui64StateChangeCount;
F_AttrElmInfo defInfo;
FLMBOOL bModifiedDatabase = FALSE;
flmAssert( pElementNode->getNodeType() == ELEMENT_NODE);
if( !pElementNode->hasAttributes())
{
goto Exit;
}
if( RC_BAD( rc = pElementNode->getFirstAttribute( this, &pAttrNode)))
{
flmAssert( rc != NE_XFLM_DOM_NODE_NOT_FOUND);
goto Exit;
}
for( ;;)
{
if( RC_BAD( rc = pAttrNode->getNameId( this, &uiNameId)))
{
goto Exit;
}
pStateInfo = sweepFindState( pStateTbl, *puiNumItems,
ELM_ATTRIBUTE_TAG, uiNameId, &uiTblSlot);
// No need to do anything if there is no state info.
if( !pStateInfo)
{
if( RC_BAD( rc = pAttrNode->getNextSibling( this, &pAttrNode)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
break;
}
continue;
}
// Stop the read transaction and start an update
// transaction.
if( getTransType() != XFLM_UPDATE_TRANS)
{
if( RC_BAD( rc = abortTrans()))
{
goto Exit;
}
*pbStartedTrans = FALSE;
if( RC_BAD( rc = beginTrans( XFLM_UPDATE_TRANS)))
{
goto Exit;
}
*pbStartedTrans = TRUE;
bModifiedDatabase = TRUE;
}
// Get the current state to see if it has changed.
if( RC_BAD( rc = m_pDict->getAttribute( this, uiNameId, &defInfo)))
{
if( rc != NE_XFLM_BAD_ATTRIBUTE_NUM)
{
goto Exit;
}
rc = NE_XFLM_OK;
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
// Read the dictionary item and get its state change count.
if( RC_BAD( rc = getDictionaryDef( ELM_ATTRIBUTE_TAG,
uiNameId, (IF_DOMNode **)&pDictDoc)))
{
goto Exit;
}
if( RC_BAD( rc = pDictDoc->getAttributeValueUINT64( this,
ATTR_STATE_CHANGE_COUNT_TAG, &ui64StateChangeCount)))
{
goto Exit;
}
if( ui64StateChangeCount != pStateInfo->ui64StateChangeCount)
{
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
// Get the next attribute before doing anything to our
// current attribute - because we may end up deleting
// pAttrNode below.
if( RC_BAD( rc = pAttrNode->getNextSibling( this,
&pNextAttrNode)))
{
if( rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
// If the item's state is still 'checking' set it to
// active.
if( pStateInfo->uiState == ATTR_ELM_STATE_CHECKING)
{
if( defInfo.m_uiState == ATTR_ELM_STATE_CHECKING)
{
if( RC_BAD( rc = changeItemState( ELM_ATTRIBUTE_TAG,
uiNameId, XFLM_ACTIVE_OPTION_STR)))
{
goto Exit;
}
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
}
else
{
// If the state is not still purge, don't do anything more
// on this attribute - set state to active, so no more purges
// will take place.
if( defInfo.m_uiState != ATTR_ELM_STATE_PURGE)
{
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
else
{
if( RC_BAD( rc = pAttrNode->deleteNode( this)))
{
if( rc != NE_XFLM_DOM_NODE_DELETED)
{
goto Exit;
}
rc = NE_XFLM_OK;
}
}
}
// If the state got changed to active, remove the thing from the
// array and decrement the item count. It means we have stopped
// processing this item.
if( pStateInfo->uiState != defInfo.m_uiState)
{
if( uiTblSlot < *puiNumItems - 1)
{
f_memmove( &pStateTbl [uiTblSlot], &pStateTbl [uiTblSlot + 1],
sizeof( ELM_ATTR_STATE_INFO) *
(*puiNumItems - 1 - uiTblSlot));
}
(*puiNumItems)--;
if( *puiNumItems == 0)
{
break;
}
}
pAttrNode->Release();
pAttrNode = NULL;
// Point pAttrNode to pNextAttrNode and steal its AddRef()
if( (pAttrNode = pNextAttrNode) == NULL)
{
break;
}
pNextAttrNode = NULL;
}
if( bModifiedDatabase)
{
// Commit the transaction
*pbStartedTrans = FALSE;
if( RC_BAD( rc = commitTrans( 0, FALSE)))
{
goto Exit;
}
// Restart the read transaction.
if( RC_BAD( rc = beginTrans( XFLM_READ_TRANS,
XFLM_NO_TIMEOUT, XFLM_DONT_POISON_CACHE)))
{
goto Exit;
}
*pbStartedTrans = TRUE;
}
Exit:
if( pDictDoc)
{
pDictDoc->Release();
}
if( pAttrNode)
{
pAttrNode->Release();
}
if( pNextAttrNode)
{
pNextAttrNode->Release();
}
if( RC_BAD( rc) && *pbStartedTrans)
{
abortTrans();
*pbStartedTrans = FALSE;
}
return( rc);
}
/****************************************************************************
Desc: Go through items in the element/attribute table and finalize the
state for each item.
****************************************************************************/
RCODE F_Db::sweepFinalizeStates(
ELM_ATTR_STATE_INFO * pStateTbl,
FLMUINT uiNumItems,
FLMBOOL * pbStartedTrans)
{
RCODE rc = NE_XFLM_OK;
ELM_ATTR_STATE_INFO * pStateInfo;
F_DOMNode * pNode = NULL;
F_DOMNode * pDictDoc = NULL;
FLMUINT uiLoop;
FLMUINT64 ui64StateChangeCount;
F_AttrElmInfo defInfo;
m_bItemStateUpdOk = TRUE;
// Stop the read transaction and start an update transaction.
abortTrans();
*pbStartedTrans = FALSE;
if( RC_BAD( rc = beginTrans( XFLM_UPDATE_TRANS)))
{
goto Exit;
}
*pbStartedTrans = TRUE;
// Check the state of all items in the table.
for (uiLoop = 0, pStateInfo = pStateTbl;
uiLoop < uiNumItems;
uiLoop++, pStateInfo++)
{
if (pStateInfo->uiDictType == ELM_ELEMENT_TAG)
{
if (RC_BAD( rc = m_pDict->getElement( this,
pStateInfo->uiDictNum, &defInfo)))
{
// Element has gone away.
if( rc != NE_XFLM_BAD_ELEMENT_NUM)
{
goto Exit;
}
rc = NE_XFLM_OK;
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
}
else
{
if (RC_BAD( rc = m_pDict->getAttribute( this,
pStateInfo->uiDictNum, &defInfo)))
{
// Attribute has gone away.
if( rc != NE_XFLM_BAD_ATTRIBUTE_NUM)
{
goto Exit;
}
rc = NE_XFLM_OK;
defInfo.m_uiState = ATTR_ELM_STATE_ACTIVE;
}
}
// Read the dictionary item and get its state change count.
if (RC_BAD( rc = getDictionaryDef( pStateInfo->uiDictType,
pStateInfo->uiDictNum,
(IF_DOMNode **)&pDictDoc)))
{
goto Exit;
}
if (RC_BAD( rc = pDictDoc->getAttributeValueUINT64( this,
ATTR_STATE_CHANGE_COUNT_TAG,
&ui64StateChangeCount)))
{
goto Exit;
}
// If the state is unchanged, purge the definition document
if (defInfo.m_uiState == pStateInfo->uiState &&
ui64StateChangeCount == pStateInfo->ui64StateChangeCount)
{
// First make sure the element or attribute is not
// referenced from an index definition.
if (pStateInfo->uiDictType == ELM_ELEMENT_TAG)
{
if( RC_BAD( rc = m_pDict->checkElementReferences(
pStateInfo->uiDictNum)))
{
if( rc != NE_XFLM_CANNOT_DEL_ELEMENT)
{
goto Exit;
}
rc = NE_XFLM_OK;
pStateInfo->uiState = ATTR_ELM_STATE_ACTIVE;
}
}
else
{
if( RC_BAD( rc = m_pDict->checkAttributeReferences(
pStateInfo->uiDictNum)))
{
if( rc != NE_XFLM_CANNOT_DEL_ATTRIBUTE)
{
goto Exit;
}
rc = NE_XFLM_OK;
pStateInfo->uiState = ATTR_ELM_STATE_ACTIVE;
}
}
if( pStateInfo->uiState == ATTR_ELM_STATE_ACTIVE)
{
// Change the state to active since it is referenced
// from an index definition
if (RC_BAD( rc = changeItemState( pStateInfo->uiDictType,
pStateInfo->uiDictNum,
XFLM_ACTIVE_OPTION_STR)))
{
goto Exit;
}
}
else
{
F_DataVector srchKey;
F_DataVector foundKey;
// Find and purge the definition document.
if (RC_BAD( rc = srchKey.setUINT( 0, pStateInfo->uiDictType)))
{
goto Exit;
}
if (RC_BAD( rc = srchKey.setUINT( 1, pStateInfo->uiDictNum)))
{
goto Exit;
}
if (RC_BAD( rc = keyRetrieve( XFLM_DICT_NUMBER_INDEX,
&srchKey, XFLM_EXACT, &foundKey)))
{
if (rc == NE_XFLM_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if (RC_BAD( rc = getNode( XFLM_DICT_COLLECTION,
foundKey.getDocumentID(), &pNode)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = RC_SET( NE_XFLM_DATA_ERROR);
}
goto Exit;
}
if (RC_BAD( rc = pNode->deleteNode( this)))
{
goto Exit;
}
}
}
defInfo.resetInfo();
}
// Commit the transaction.
*pbStartedTrans = FALSE;
if (RC_BAD( rc = commitTrans( 0, FALSE)))
{
goto Exit;
}
Exit:
if( RC_BAD( rc) && *pbStartedTrans)
{
abortTrans();
*pbStartedTrans = FALSE;
}
m_bItemStateUpdOk = FALSE;
if (pNode)
{
pNode->Release();
}
if (pDictDoc)
{
pDictDoc->Release();
}
return( rc);
}