Пример #1
0
/********************************************************************
Desc: ?
*********************************************************************/
void ViewSearch(
	void)
{
	FLMBYTE	LFH[ LFH_SIZE];
	FLMUINT	FileOffset;
	FLMUINT	RootBlkAddress;
	BLK_EXP	BlkExp;

	if (!gv_bViewHdrRead)
		ViewReadHdr();

	/* Set flags */

	for( ;;)
	{
		gv_bViewPoppingStack = FALSE;

		/* Get the LFH information for the logical file */

		if (!ViewGetLFH( gv_uiViewSearchLfNum, LFH, &FileOffset))
		{
			ViewShowError( "Could not get LFH for logical file");
			return;
		}
		RootBlkAddress = FB2UD( &LFH [LFH_ROOT_BLK_OFFSET]);
		if (RootBlkAddress == 0xFFFFFFFF)
		{
			ViewShowError( "Logical file is empty");
			return;
		}

		BlkExp.Level = 0xFF;
		BlkExp.Type = 0xFF;
//		BlkExp.Type = BHT_NON_LEAF;
		BlkExp.NextAddr = BlkExp.PrevAddr = 0xFFFFFFFF;
		BlkExp.LfNum = gv_uiViewSearchLfNum;
		gv_bViewEnabled = FALSE;
		gv_bViewSearching = TRUE;
		ViewBlocks( RootBlkAddress, RootBlkAddress, &BlkExp);

		/* Reset Search flag before returning so everything will be back to */
		/* normal. */

		gv_bViewSearching = FALSE;

		/* If the ViewBlocks did not set up for another search, we are */
		/* done, otherwise keep-a-goin */

		if (!gv_bViewPoppingStack)
			break;
	}
}
/****************************************************************************
Desc:	Split the root block and make two new non-leaf blocks.
		The secret here is that the root block never moves (cheers!).
		This takes a little longer but is worth the work because the
		root block never goes out to disk and is not in the cache.
****************************************************************************/
RCODE F_BtreeRoot::split(
    void *			pvCurEntry,
    FLMUINT			uiCurChildAddr)
{
    RCODE				rc = NE_FLM_OK;
    FLMBYTE *		pucEntry;
    FLMBYTE *		pucChildAddr;
    F_BtreeBlk *		pLeftBlk;
    F_BtreeBlk *		pRightBlk;
    F_BtreeBlk *		pBlk;
    FLMUINT			uiChildAddr;
    FLMUINT			uiPos;
    FLMUINT			uiEntryCount = entryCount();
    FLMUINT			uiMid = (uiEntryCount + 1) >> 1;

    if (RC_BAD( rc = setupTree( NULL, ACCESS_BTREE_NON_LEAF,
                                &pLeftBlk, &pRightBlk)))
    {
        goto Exit;
    }

    // Call search entry once just to setup for insert.

    (void) pLeftBlk->searchEntry( ENTRY_POS( 0));

    // Take the entries from the root block and move into leafs.

    for (uiPos = 0; uiPos <= uiMid; uiPos++)
    {
        pucEntry = ENTRY_POS( uiPos);
        pucChildAddr = pucEntry + m_uiEntrySize;
        uiChildAddr = (FLMUINT)FB2UD(pucChildAddr);

        if (RC_BAD( rc = pLeftBlk->insertEntry( pucEntry, uiChildAddr)))
        {
            goto Exit;
        }
    }

    // Call search entry once just to setup for insert.

    (void) pRightBlk->searchEntry( ENTRY_POS( 0));

    for (uiPos = uiMid + 1; uiPos < uiEntryCount; uiPos++)
    {
        pucEntry = ENTRY_POS( uiPos);
        pucChildAddr = pucEntry + m_uiEntrySize;
        uiChildAddr = (FLMUINT)FB2UD(pucChildAddr);

        if ((rc = pRightBlk->searchEntry( pucEntry )) != NE_FLM_NOT_FOUND)
        {
            rc = RC_SET_AND_ASSERT( NE_FLM_FAILURE);
            goto Exit;
        }

        if (RC_BAD( rc = pRightBlk->insertEntry( pucEntry, uiChildAddr)))
        {
            goto Exit;
        }
    }

    // Reset the root block and insert new midpoint.

    entryCount( 0);
    lemBlk( pRightBlk->blkAddr());	// Duplicated just in case.
    pucEntry = ENTRY_POS( uiMid);

    if ((rc = searchEntry( pucEntry )) != NE_FLM_NOT_FOUND)
    {
        rc = RC_SET_AND_ASSERT( NE_FLM_FAILURE);
        goto Exit;
    }

    if (RC_BAD( rc = insertEntry( pucEntry, pLeftBlk->blkAddr() )))
    {
        goto Exit;
    }

    // Insert the current entry (parameters) into the left or right blk.
    // This could be done a number of different ways.
    (void) searchEntry( pvCurEntry, &uiChildAddr);
    if (RC_BAD( rc = readBlk( uiChildAddr, ACCESS_BTREE_NON_LEAF, &pBlk)))
    {
        goto Exit;
    }
    (void) pBlk->searchEntry( pvCurEntry);
    if (RC_BAD( rc = pBlk->insertEntry( pvCurEntry, uiCurChildAddr)))
    {
        goto Exit;
    }

Exit:

    return( rc);
}
/****************************************************************************
Desc:	Move first half of entries into new block.  Reset previous block
		to point to new block.  Add new last entry in new block to parent.
		Fixup prev/next linkages.
****************************************************************************/
RCODE F_BtreeBlk::split(
    F_BtreeRoot *	pRoot,
    FLMBYTE *		pucCurEntry,		// (in) Contains entry to insert
    FLMUINT			uiCurBlkAddr,		// (in) Blk addr if non-leaf
    FLMBYTE *		pucParentEntry,	// (out) Entry to insert into parent.
    FLMUINT *		puiNewBlkAddr)		// (out) New blk addr to insert into parent.
{
    RCODE				rc = NE_FLM_OK;
    F_BtreeBlk *		pPrevBlk;
    F_BtreeBlk *		pNewBlk = NULL;
    FLMBYTE *		pucEntry = NULL;
    FLMBYTE *		pucMidEntry;
    FLMBYTE *		pucChildAddr;
    FLMUINT			uiChildAddr;
    FLMUINT			uiPrevBlkAddr;
    FLMUINT			uiMid;
    FLMUINT			uiPos;
    FLMUINT			uiMoveBytes;
    FLMBOOL			bInserted = FALSE;

    // Allocate a new block for the split.

    if (RC_BAD( rc = pRoot->newBlk( &pNewBlk, blkType() )))
    {
        goto Exit;
    }
    pNewBlk->AddRef();				// Pin the block - may get flushed out.


    // the last half into the new block, but that would force the parent
    // entry to be changed.  This may take a little longer, but it is much
    // more easier to code.

    // Call search entry once just to setup for insert.

    (void) pNewBlk->searchEntry( ENTRY_POS( 0));

    // get the count and move more then half into the new block.

    uiMid = (entryCount() + 5) >> 1;
    uiChildAddr = FBTREE_END;

    for (uiPos = 0; uiPos < uiMid; uiPos++)
    {
        pucEntry = ENTRY_POS( uiPos);
        if (blkType() != ACCESS_BTREE_LEAF)
        {
            pucChildAddr = pucEntry + m_uiEntrySize;
            uiChildAddr = (FLMUINT)FB2UD(pucChildAddr);
        }

        // m_uiPosition automatically gets incremented.

        if (RC_BAD( rc = pNewBlk->insertEntry( pucEntry, uiChildAddr)))
        {
            RC_UNEXPECTED_ASSERT( rc);
            goto Exit;
        }
    }

    if (m_uiPosition < uiMid)
    {

        // Insert this entry now

        bInserted = TRUE;
        (void) pNewBlk->searchEntry( pucCurEntry);
        if (RC_BAD( rc = pNewBlk->insertEntry( pucCurEntry, uiCurBlkAddr)))
        {
            goto Exit;
        }
    }

    // Let caller insert into parent entry.  This rids us of recursion.

    f_memcpy( pucParentEntry, pucEntry, m_uiEntrySize);

    // Move the rest down

    pucEntry = ENTRY_POS( 0);
    pucMidEntry = ENTRY_POS( uiMid);

    entryCount( entryCount() - uiMid);
    uiMoveBytes = entryCount() * (m_uiEntrySize + m_uiEntryOvhd);
    flmAssert( uiMoveBytes < DYNSSET_BLOCK_SIZE - sizeof( FixedBlkHdr));
    f_memmove( pucEntry, pucMidEntry, uiMoveBytes);

    if( !bInserted)
    {

        // m_uiPosition -= uiMid;

        (void) searchEntry( pucCurEntry);
        if (RC_BAD( rc = insertEntry( pucCurEntry, uiCurBlkAddr)))
        {
            goto Exit;
        }
    }

    // VISIT: Could position stack to point to current element to insert.

    // Fixup the prev/next block linkages.

    if (prevBlk() != FBTREE_END)
    {
        if (RC_BAD( rc = pRoot->readBlk( prevBlk(), blkType(), &pPrevBlk )))
        {
            goto Exit;
        }

        pPrevBlk->nextBlk( pNewBlk->blkAddr());
        uiPrevBlkAddr = pPrevBlk->blkAddr();
    }
    else
    {
        uiPrevBlkAddr = FBTREE_END;
    }
    pNewBlk->prevBlk( uiPrevBlkAddr);
    pNewBlk->nextBlk( blkAddr());
    prevBlk( pNewBlk->blkAddr());

    *puiNewBlkAddr = pNewBlk->blkAddr();

Exit:

    if (pNewBlk)
    {
        pNewBlk->Release();
    }

    return( rc);
}
/****************************************************************************
Desc:	Search a single block tree.  Position for get* or for insert.
		Do a binary search on all of the entries to find a match.
		If no match then position to the entry where an insert
		will take place.
****************************************************************************/
RCODE F_BtreeBlk::searchEntry(
    void *		pvEntry,
    FLMUINT *	puiChildAddr,
    void *		pvFoundEntry)
{
    RCODE			rc = RC_SET( NE_FLM_NOT_FOUND);
    FLMUINT		uiLow;
    FLMUINT		uiMid;
    FLMUINT		uiHigh;
    FLMUINT		uiTblSize;
    FLMINT		iCompare;

    // check for zero entries.

    if (!entryCount())
    {
        uiMid = 0;
        goto Exit;
    }
    uiHigh = uiTblSize = entryCount() - 1;
    uiLow = 0;
    for(;;)
    {
        uiMid = (uiLow + uiHigh) >> 1;		// (uiLow + uiHigh) / 2

        // Use compare routine

        if (m_fnCompare)
        {
            iCompare = m_fnCompare( pvEntry, ENTRY_POS( uiMid), m_pvUserData);
        }
        else
        {
            iCompare = f_memcmp( pvEntry, ENTRY_POS( uiMid), m_uiEntrySize);
        }

        if (iCompare == 0)
        {
            if (pvFoundEntry)
            {
                f_memcpy( pvFoundEntry, ENTRY_POS( uiMid), m_uiEntrySize);
            }
            rc = NE_FLM_OK;
            goto Exit;
        }

        // Check if we are done - where wLow equals uiHigh or mid is at end.

        if (iCompare < 0)
        {
            if (uiMid == uiLow || uiLow == uiHigh)
            {
                break;
            }
            uiHigh = uiMid - 1;					// Too high
        }
        else
        {
            if (uiMid == uiHigh || uiLow == uiHigh)
            {

                // Go up one for the correct position?

                uiMid++;
                break;
            }
            uiLow = uiMid + 1;					// Too low
        }
    }

Exit:

    m_uiPosition = uiMid;
    if (puiChildAddr && blkType() != ACCESS_BTREE_LEAF)
    {
        if (uiMid == entryCount())
        {
            *puiChildAddr = lemBlk();
        }
        else
        {
            FLMBYTE *	pucChildAddr = ENTRY_POS(uiMid) + m_uiEntrySize;
            *puiChildAddr = (FLMUINT)FB2UD( pucChildAddr);
        }
    }
    return( rc);
}
Пример #5
0
/***************************************************************************
Name:    ViewOutputLFH2_0
Desc:    This routine outputs the information in a single LFH - for a
			single logical file - FLAIM 1.5 and above.
*****************************************************************************/
FSTATIC FLMINT ViewOutputLFH2_0(
	FLMUINT		Col,
	FLMUINT  *	RowRV,
	FLMBYTE *   LFH,
	FLMUINT     Ref,
	FLMUINT     FileOffset
	)
{
	FLMUINT     LabelWidth = 35;
	FLMUINT     Row = *RowRV;
	FLMUINT		BlkAddress;
	FLMBYTE		TempBuf [80];
	eColorType	bc = FLM_BLACK;
	eColorType	fc = FLM_LIGHTGRAY;
	eColorType	mbc = FLM_BLACK;
	eColorType	mfc = FLM_WHITE;
	eColorType	sbc = FLM_BLUE;
	eColorType	sfc = FLM_WHITE;
	FLMUINT     Option;
	FLMUINT		lfNum;

	/* Output Logical File Name */

	lfNum = FB2UW( &LFH [LFH_LF_NUMBER_OFFSET]);
	switch (lfNum)
	{
		case FLM_DICT_CONTAINER:
			f_strcpy( (char *)TempBuf, "LOCAL_DICT");
			break;
		case FLM_DATA_CONTAINER:
			f_strcpy( (char *)TempBuf, "DEFAULT_DATA");
			break;
		case FLM_TRACKER_CONTAINER:
			f_strcpy( (char *)TempBuf, "TRACKER_CONTAINER");
			break;
		case FLM_DICT_INDEX:
			f_strcpy( (char *)TempBuf, "LOCAL_DICT_IX");
			break;
		default:
			switch (LFH [LFH_TYPE_OFFSET])
			{
				case LF_INDEX:
					f_sprintf( (char *)TempBuf, "INDEX_%u", (unsigned)lfNum);
					break;
				case LF_CONTAINER:
					f_sprintf( (char *)TempBuf, "CONTAINER_%u", (unsigned)lfNum);
					break;
				default:
					f_sprintf( (char *)TempBuf, "UNKNOWN_TYPE[%u]_%u",
						(unsigned)LFH [LFH_TYPE_OFFSET], (unsigned)lfNum);
					break;
			}
			break;
	}

	if (!ViewAddMenuItem( LBL_LOGICAL_FILE_NAME, LabelWidth,
				VAL_IS_TEXT_PTR,
				(FLMUINT)((FLMBYTE *)(&TempBuf [0])), 0,
				0, VIEW_INVALID_FILE_OFFSET, (FLMUINT)f_strlen( (const char *)TempBuf),
				MOD_DISABLED,
				Col, Row++, 0, FLM_GREEN, FLM_WHITE,
				FLM_GREEN, FLM_WHITE))
		return( 0);

	/* Adjust column and label width so the rest is indented */

	Col += 2;
	LabelWidth -= 2;

	/* Output Logical File Number */

	if (!ViewAddMenuItem( LBL_LOGICAL_FILE_NUMBER, LabelWidth,
				VAL_IS_NUMBER | DISP_DECIMAL,
				(FLMUINT)(lfNum), 0,
				0, FileOffset + LFH_LF_NUMBER_OFFSET, 0,
				MOD_FLMUINT | MOD_DECIMAL,
				Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output Logical File Type */

	FormatLFType( TempBuf, LFH [LFH_TYPE_OFFSET]);
	if (!ViewAddMenuItem( LBL_LOGICAL_FILE_TYPE, LabelWidth,
				VAL_IS_TEXT_PTR,
				(FLMUINT)((FLMBYTE *)(&TempBuf [0])), 0,
				0, FileOffset + LFH_LF_NUMBER_OFFSET, 0,
				MOD_FLMBYTE | MOD_HEX,
				Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	/* Output the root block address */

	if ((BlkAddress = FB2UD( &LFH [LFH_ROOT_BLK_OFFSET])) == 0xFFFFFFFF)
		Option = 0;
	else
		Option = LFH_OPTION_ROOT_BLOCK | Ref;
	if (!ViewAddMenuItem( LBL_ROOT_BLOCK_ADDRESS, LabelWidth,
				VAL_IS_NUMBER | DISP_HEX_DECIMAL,
				BlkAddress, 0,
				0, FileOffset + LFH_ROOT_BLK_OFFSET, 0,
				MOD_FLMUINT | MOD_HEX,
				Col, Row++, Option,
				!Option ? bc : mbc,
				!Option ? fc : mfc,
				!Option ? bc : sbc,
				!Option ? fc : sfc))
		return( 0);

	/* Output the next DRN */

	if (!ViewAddMenuItem( LBL_NEXT_DRN, LabelWidth,
				VAL_IS_NUMBER | DISP_DECIMAL,
				FB2UD( &LFH [LFH_NEXT_DRN_OFFSET]), 0,
				0, FileOffset + LFH_NEXT_DRN_OFFSET, 0,
				MOD_FLMUINT | MOD_DECIMAL,
				Col, Row++, 0, bc, fc, bc, fc))
		return( 0);

	*RowRV = Row + 1;
	return( 1);
}
Пример #6
0
/***************************************************************************
Name:    ViewLogicalFile
Desc:    This routine displays a single logical file and allows the user
			to press menu keys while displaying the information.
*****************************************************************************/
void ViewLogicalFile(
	FLMUINT		lfNum
	)
{
	FLMUINT     Option;
	VIEW_INFO   SaveView;
	FLMUINT     Done = 0;
	FLMUINT     Repaint = 1;
	FLMBYTE		LFH[ LFH_SIZE];
	BLK_EXP     BlkExp2;
	FLMUINT     BlkAddress2 = 0;

	/* Loop getting commands until the hit the exit key */

	ViewReset( &SaveView);
	while ((!Done) && (!gv_bViewPoppingStack))
	{
		if (Repaint)
		{
			if (!ViewSetupLogicalFileMenu( lfNum, LFH))
				Done = 1;
		}
		if (!Done)
		{
			Repaint = 1;
			Option = ViewGetMenuOption();
			switch( Option)
			{
				case ESCAPE_OPTION:
					Done = 1;
					break;
				case SEARCH_OPTION:
					{
						VIEW_MENU_ITEM_p  vp = gv_pViewMenuCurrItem;

						/* Determine which logical file, if any we are pointing at */

						while ((vp != NULL) &&
									(vp->iLabelIndex != LBL_LOGICAL_FILE_NAME))
							vp = vp->PrevItem;
						if (vp != NULL)
						{
							while ((vp != NULL) &&
										(vp->iLabelIndex != LBL_LOGICAL_FILE_NUMBER))
								vp = vp->NextItem;
						}
						if (vp != NULL)
						{
							gv_uiViewSearchLfNum = (FLMUINT)vp->Value;
							if (ViewGetKey())
								gv_bViewPoppingStack = TRUE;
						}
						else
							ViewShowError( "Position cursor to a logical file before searching");
					}
					break;
				default:
					if ((Option & LFH_OPTION_ROOT_BLOCK) ||
						 (Option & LFH_OPTION_LAST_BLOCK))
					{
						if (Option & LFH_OPTION_ROOT_BLOCK)
						{
							BlkExp2.Level = 0xFF;
							BlkExp2.Type = 0xFF;
							BlkAddress2 = FB2UD( &LFH [LFH_ROOT_BLK_OFFSET]);
							BlkExp2.NextAddr = BlkExp2.PrevAddr = 0xFFFFFFFF;
						}
						else
						{
							flmAssert( 0);
						}
						BlkExp2.LfNum = FB2UW( &LFH [LFH_LF_NUMBER_OFFSET]);
						ViewBlocks( BlkAddress2, BlkAddress2, &BlkExp2);
					}
					else if (Option & LOGICAL_FILE_OPTION)
						ViewLogicalFile( (FLMUINT)(Option & (~(LOGICAL_FILE_OPTION))));
					else
						Repaint = 0;
					break;
			}
		}
	}
	ViewRestore( &SaveView);
}
Пример #7
0
/****************************************************************************
Desc:	This routine aborts an active transaction for a particular
		database.  If the database is open via a server, a message is
		sent to the server to abort the transaction.  Otherwise, the
		transaction is rolled back locally.
****************************************************************************/
RCODE flmAbortDbTrans(
	FDB *				pDb,
	FLMBOOL			bOkToLogAbort)
{
	RCODE				rc = FERR_OK;
	FFILE *			pFile = pDb->pFile;
	FLMUINT			uiTransType;
	FLMBYTE *		pucLastCommittedLogHdr;
	FLMBYTE *		pucUncommittedLogHdr;
	FLMBOOL			bDumpedCache = FALSE;
	DB_STATS *		pDbStats = pDb->pDbStats;
	FLMBOOL			bKeepAbortedTrans;
	FLMUINT			uiTransId;
	FLMBOOL			bInvisibleTrans;

	// Get transaction type

	if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS)
	{
		goto Exit;
	}

	// No recovery required if it is a read transaction.

	if (uiTransType == FLM_READ_TRANS)
	{

		if( pDb->KrefCntrl.bKrefSetup)
		{
			// KrefCntrlFree could be called w/o checking bKrefSetup because
			// it checks the flag, but it is more optimal to check the
			// flag before making the call because most of the time it will
			// be false.

			KrefCntrlFree( pDb);
		}

		goto Unlink_From_Trans;
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID,
			0, 0, FERR_OK, "TAbrt");
#endif

	pFile->pRfl->clearLogHdrs();

	// If the transaction had no update operations, restore it
	// to its pre-transaction state - make it appear that no
	// transaction ever happened.

	pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0];
	pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];
	uiTransId = pDb->LogHdr.uiCurrTransID;

	// Free up all keys associated with this database.  This is done even
	// if we didn't have any update operations because the KREF may
	// have been initialized by key generation operations performed
	// by cursors, etc.

	KrefCntrlFree( pDb);

	// Free any index counts we may have allocated.

	FSFreeIxCounts( pDb);
	
	if (pDb->bHadUpdOper)
	{
		// Dump any BLOB structures that should be aborted.

		FBListAfterAbort( pDb);

		// Dump any start and stop indexing stubs that should be aborted.

		flmIndexingAfterAbort( pDb);

		// Log the abort record to the rfl file, or throw away the logged
		// records altogether, depending on the LOG_KEEP_ABORTED_TRANS_IN_RFL
		// flag.  If the RFL volume is bad, we will not attempt to keep this
		// transaction in the RFL.

		if (!pFile->pRfl->seeIfRflVolumeOk())
		{
			bKeepAbortedTrans = FALSE;
		}
		else
		{
			bKeepAbortedTrans =
				(pucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL])
				? TRUE
				: FALSE;
		}
	}
	else
	{
		bKeepAbortedTrans = FALSE;
	}

	// Log an abort transaction record to the roll-forward log or
	// throw away the entire transaction, depending on the
	// bKeepAbortedTrans flag.

	// If the transaction is being "dumped" because of a failed commit,
	// don't log anything to the RFL.

	if( bOkToLogAbort)
	{
		flmAssert( pDb->LogHdr.uiCurrTransID == pFile->pRfl->getCurrTransID());
		if (RC_BAD( rc = pFile->pRfl->logEndTransaction(
									RFL_TRNS_ABORT_PACKET, !bKeepAbortedTrans)))
		{
			goto Exit1;
		}
	}
#ifdef FLM_DEBUG
	else
	{
		// If bOkToLogAbort is FALSE, this always means that either a
		// commit failed while trying to log an end transaction packet or a
		// commit packet was logged and the transaction commit subsequently
		// failed for some other reason.  In either case, the RFL should be
		// in a good state, with its current transaction ID reset to 0.  If
		// not, either bOkToLogAbort is being used incorrectly by the caller
		// or there is a bug in the RFL logic.

		flmAssert( pFile->pRfl->getCurrTransID() == 0);
	}
#endif

	// If there were no operations in the transaction, restore
	// everything as if the transaction never happened.

	if (!pDb->bHadUpdOper)
	{
		f_mutexLock( gv_FlmSysData.hShareMutex);
		pFile->uiUpdateTransID = 0;
		f_mutexUnlock( gv_FlmSysData.hShareMutex);

		// Pretend we dumped cache - shouldn't be any to worry about at
		// this point.

		bDumpedCache = TRUE;
		goto Exit1;
	}

	// Dump ALL modified cache blocks associated with the DB.
	// NOTE: This needs to be done BEFORE the call to flmGetLogHdrInfo
	// below, because that call will change pDb->LogHdr.uiCurrTransID,
	// and that value is used by flmRcaAbortTrans.

	ScaFreeModifiedBlocks( pDb);
	flmRcaAbortTrans( pDb);
	bDumpedCache = TRUE;

	// Reset the LogHdr from the last committed log header in pFile.

	flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr);
	if (RC_BAD( rc = flmPhysRollback( pDb,
				 (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_ROLLBACK_EOF]),
				 pFile->uiFirstLogBlkAddress, FALSE, 0)))
	{
		goto Exit1;
	}

	f_mutexLock( gv_FlmSysData.hShareMutex);

	// Put the new transaction ID into the log header even though
	// we are not committing.  We want to keep the transaction IDs
	// incrementing even though we aborted.

	UD2FBA( (FLMUINT32)uiTransId,
			&pucLastCommittedLogHdr [LOG_CURR_TRANS_ID]);

	// Preserve where we are at in the roll-forward log.  Even though
	// the transaction aborted, we may have kept it in the RFL instead of
	// throw it away.

	f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_FILE_NUM],
				 &pucUncommittedLogHdr [LOG_RFL_FILE_NUM], 4);
	f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET],
				 &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET], 4);
	f_memcpy( &pucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM],
				 &pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM],
				 F_SERIAL_NUM_SIZE);
	f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM],
				 &pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM],
				 F_SERIAL_NUM_SIZE);

	// The following items tell us where we are at in the roll-back log.
	// During a transaction we may log blocks for the checkpoint or for
	// read transactions.  So, even though we are aborting this transaction,
	// there may be other things in the roll-back log that we don't want
	// to lose.  These items should not be reset until we do a checkpoint,
	// which is when we know it is safe to throw away the entire roll-back log.

	f_memcpy( &pucLastCommittedLogHdr [LOG_ROLLBACK_EOF],
				 &pucUncommittedLogHdr [LOG_ROLLBACK_EOF], 4);
	f_memcpy( &pucLastCommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR],
				 &pucUncommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR], 4);

	f_mutexUnlock( gv_FlmSysData.hShareMutex);

	pFile->pRfl->commitLogHdrs( pucLastCommittedLogHdr,
							pFile->ucCheckpointLogHdr);

Exit1:

	// Dump cache, if not done above.

	if (!bDumpedCache)
	{
		ScaFreeModifiedBlocks( pDb);
		flmRcaAbortTrans( pDb);
		bDumpedCache = TRUE;
	}

	// Throw away IXD_FIXUPs

	if (pDb->pIxdFixups)
	{
		IXD_FIXUP *	pIxdFixup;
		IXD_FIXUP *	pDeleteIxdFixup;

		pIxdFixup = pDb->pIxdFixups;
		while (pIxdFixup)
		{
			pDeleteIxdFixup = pIxdFixup;
			pIxdFixup = pIxdFixup->pNext;
			f_free( &pDeleteIxdFixup);
		}
		pDb->pIxdFixups = NULL;
	}

	if (uiTransType != FLM_READ_TRANS &&
		 gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmTransEventCallback( F_EVENT_ABORT_TRANS, (HFDB)pDb, rc,
						uiTransId);
	}

Unlink_From_Trans:

	bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE;
	if (pDb->uiFlags & FDB_HAS_WRITE_LOCK)
	{
		RCODE	tmpRc;

		if (RC_BAD( tmpRc = pFile->pRfl->completeTransWrites( pDb, FALSE, FALSE)))
		{
			if (RC_OK( rc))
			{
				rc = tmpRc;
			}
		}
	}

	// Unlink the database from the transaction
	// structure as well as from the FLDICT structure.

	flmUnlinkDbFromTrans( pDb, FALSE);

	if (pDbStats)
	{
		FLMUINT64	ui64ElapMilli = 0;

		flmAddElapTime( &pDb->TransStartTime, &ui64ElapMilli);
		pDbStats->bHaveStats = TRUE;
		if (uiTransType == FLM_READ_TRANS)
		{
			pDbStats->ReadTransStats.AbortedTrans.ui64Count++;
			pDbStats->ReadTransStats.AbortedTrans.ui64ElapMilli +=
					ui64ElapMilli;
			if (bInvisibleTrans)
			{
				pDbStats->ReadTransStats.InvisibleTrans.ui64Count++;
				pDbStats->ReadTransStats.InvisibleTrans.ui64ElapMilli +=
					ui64ElapMilli;
			}
		}
		else
		{
			pDbStats->UpdateTransStats.AbortedTrans.ui64Count++;
			pDbStats->UpdateTransStats.AbortedTrans.ui64ElapMilli +=
					ui64ElapMilli;
		}
	}

	if (pDb->pStats)
	{
		(void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats);
	}

Exit:

	return( rc);
}
Пример #8
0
/****************************************************************************
Desc: 	Retrieves the last commit sequence number of a database.
Notes: 	Whenever a transaction is committed, FLAIM increments the commit
		 	sequence number to indicate that the database has been modified.
			An application may use this routine to determine if the database
			has been modified.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmDbGetCommitCnt(
	HFDB				hDb,
	FLMUINT *		puiCommitCount)
{
	RCODE			rc = FERR_OK;
	FDB *			pDb = (FDB *)hDb;
	FLMBOOL		bIgnore;

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);

		CS_CONTEXT *	pCSContext = pDb->pCSContext;
		FCL_WIRE			Wire( pCSContext, pDb);

		// Send a request to get the commit count

		if (RC_BAD( rc = Wire.sendOp( 
			FCS_OPCLASS_DATABASE, FCS_OP_GET_COMMIT_CNT)))
		{
			goto Exit;
		}

		if (RC_BAD( rc = Wire.sendTerminate()))
		{
			goto Transmission_Error;
		}

		// Read the response.
	
		if (RC_BAD( rc = Wire.read()))
		{
			goto Transmission_Error;
		}
		*puiCommitCount = (FLMUINT)Wire.getCount();

		rc = Wire.getRCode();
		goto ExitCS;

Transmission_Error:

		pCSContext->bConnectionGood = FALSE;
		goto ExitCS;
	}

	if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS,
										FDB_TRANS_GOING_OK, 0, &bIgnore)))
	{
		goto Exit;
	}

	// See if we have a transaction going which should be aborted.

	if (pDb->uiTransType != FLM_NO_TRANS)
	{
		if (flmCheckBadTrans( pDb))
		{
			rc = RC_SET( FERR_ABORT_TRANS);
			goto Exit;
		}
	}

	f_mutexLock( gv_FlmSysData.hShareMutex);
	*puiCommitCount = (FLMUINT)FB2UD(
			&pDb->pFile->ucLastCommittedLogHdr [LOG_COMMIT_COUNT]);
	f_mutexUnlock( gv_FlmSysData.hShareMutex);

Exit:
ExitCS:

	flmExit( FLM_DB_GET_COMMIT_CNT, pDb, rc);
	return( rc);
}
Пример #9
0
/********************************************************************
Desc: ?
*********************************************************************/
FLMINT ViewGetKey( void)
{
	RCODE				rc = FERR_OK;
	FlmRecord *		pKey = NULL;
	void *			pvFld;
	char				Prompt [80];
	FLMUINT			Num;
	FLMUINT			ValEntered;
	FLMUINT			Len;
	char				TempBuf [80];
	FLMUINT			NumFields;
	FLMUINT			i;
	FLMINT			GetOK;
	FLMBYTE			FieldName [80];
	FLMBYTE			FieldType [16];
	FLMINT			KeyEntered = FALSE;
	FLMBYTE			LFH[ LFH_SIZE];
	FLMUINT			FileOffset;
	LFILE *			pLFile = NULL;
	IXD *				pIxd;
	IFD *				pIfd;
	FLMUINT			uiRootBlkAddress;
	FLMBOOL			bTruncated;

	if (!gv_bViewHdrRead)
		ViewReadHdr();

	/* See if we can get dictionary information. */

	ViewGetDictInfo();
	if (gv_bViewHaveDictInfo)
	{

		/* Find the logical file */

		if ((RC_BAD( fdictGetIndex( ((FDB *)gv_hViewDb)->pDict,
				((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
				gv_uiViewSearchLfNum, &pLFile, NULL))) &&
				(RC_BAD( fdictGetContainer( ((FDB *)gv_hViewDb)->pDict, 
				gv_uiViewSearchLfNum, &pLFile))))
		{
			pLFile = NULL;
		}
	}

	/* See if we have a valid logical file */

	if ((gv_uiViewSearchLfNum == FLM_DATA_CONTAINER) ||
			(gv_uiViewSearchLfNum == FLM_DICT_CONTAINER) ||
			(pLFile))
	{

		/* Get the LFH information for the logical file */

		if (!ViewGetLFH( gv_uiViewSearchLfNum, LFH, &FileOffset))
		{
			ViewShowError( "Could not get LFH for logical file");
			return( FALSE);
		}
		uiRootBlkAddress = FB2UD( &LFH [LFH_ROOT_BLK_OFFSET]);

		if (uiRootBlkAddress == 0xFFFFFFFF)
		{
			ViewShowError( "Logical file is empty");
			return( FALSE);
		}
	}
	else
	{
		ViewShowError( "Logical file not defined");
		return( FALSE);
	}

	if ((gv_uiViewSearchLfNum == FLM_DATA_CONTAINER) ||
		 (gv_uiViewSearchLfNum == FLM_DICT_CONTAINER) ||
		 ((pLFile) &&
		  (pLFile->uiLfType == LF_CONTAINER)))
	{
		if (gv_uiViewSearchLfNum == FLM_DICT_CONTAINER)
			f_strcpy( TempBuf, "Enter Dictionary Record Number: ");
		else if (gv_uiViewSearchLfNum == FLM_DATA_CONTAINER)
			f_strcpy( TempBuf, "Enter Data Container Record Number: ");
		else
			f_sprintf( (char *)TempBuf, 
				"Enter Record Number For Container %u: ", 
				(unsigned)gv_uiViewSearchLfNum);
		if ((!ViewGetNum( TempBuf, &Num, FALSE, 4,
										 0xFFFFFFFF, &ValEntered)) ||
				(!ValEntered))
			return( FALSE);
		f_UINT32ToBigEndian( (FLMUINT32)Num, gv_ucViewSearchKey);
		gv_uiViewSearchKeyLen = 4;
		return( TRUE);
	}

	/* At this point, we are dealing with an index. */

	if (gv_uiViewSearchLfNum == FLM_DICT_INDEX)
	{
		FLMUINT	 wTagType = 0;
		FLMUINT	 wElmLen;

		while (!wTagType)
		{
			if ((!ViewEditText( "Enter Type:", 
									TempBuf, sizeof( TempBuf), &ValEntered)) ||
				 (!ValEntered))
				return( FALSE);
			else if ((f_stricmp( TempBuf, "F") == 0) ||
						(f_stricmp( TempBuf, "FIELD") == 0))
			{
				wTagType = FLM_FIELD_TAG;
			}
			else if ((f_stricmp( TempBuf, "I") == 0) ||
						(f_stricmp( TempBuf, "INDEX") == 0))
			{
				wTagType = FLM_INDEX_TAG;
			}
			else if ((f_stricmp( TempBuf, "C") == 0) ||
						(f_stricmp( TempBuf, "CONTAINER") == 0))
			{
				wTagType = FLM_CONTAINER_TAG;
			}
			else if ((f_stricmp( TempBuf, "A") == 0) ||
						(f_stricmp( TempBuf, "AREA") == 0))
			{
				wTagType = FLM_AREA_TAG;
			}
			else
			{
				ViewShowError( "Illegal type, must be F)ield, I)ndex, C)ontainer, R)ecord, or A)rea");
				wTagType = 0;
			}
		}
		gv_ucViewSearchKey [0] = KY_CONTEXT_PREFIX;
		f_UINT16ToBigEndian( (FLMUINT16)wTagType, &gv_ucViewSearchKey [1]);
		gv_uiViewSearchKeyLen += KY_CONTEXT_LEN;
		gv_ucViewSearchKey [gv_uiViewSearchKeyLen++] = COMPOUND_MARKER;

		if (!ViewEditText( "Enter Name:", TempBuf, sizeof( TempBuf), &ValEntered))
			return( FALSE);

		/* Collate the name. */

		wElmLen = MAX_KEY_SIZ - gv_uiViewSearchKeyLen;
		if (RC_BAD( rc = KYCollateValue( &gv_ucViewSearchKey [gv_uiViewSearchKeyLen],
									&wElmLen,
									(const FLMBYTE *)TempBuf,
									(FLMUINT)f_strlen( TempBuf), FLM_TEXT_TYPE,
									MAX_KEY_SIZ,
									NULL, NULL,
									gv_ViewHdrInfo.FileHdr.uiDefaultLanguage,
									FALSE, FALSE, FALSE, &bTruncated)))
		{
			ViewShowRCError( "collating name", rc);
			return( FALSE);
		}
		gv_uiViewSearchKeyLen += wElmLen;
		return( TRUE);
	}
	else if (!pLFile)
	{
		ViewShowError( "Cannot get logical file information");
		return( FALSE);
	}
	else if (RC_BAD( fdictGetIndex( ((FDB *)gv_hViewDb)->pDict,
			((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
			gv_uiViewSearchLfNum, &pLFile, &pIxd)))
	{
		ViewShowError( "Cannot get index field information");
		return( FALSE);
	}
	else
	{
		pIfd = pIxd->pFirstIfd;
		NumFields = pIxd->uiNumFlds;

		if (!(pIfd->uiFlags & IFD_COMPOUND))
		{
			NumFields = 1;
		}

		if( (pKey = f_new FlmRecord) == NULL)
		{
			rc = RC_SET( FERR_MEM);
			ViewShowRCError( "creating key", rc);
			goto Exit_False;
		}

		if (RC_BAD( rc = pKey->insertLast( 0, FLM_KEY_TAG,
										FLM_CONTEXT_TYPE, &pvFld)))
		{
			ViewShowRCError( "adding key tag", rc);
			goto Exit_False;
		}

		/* Ask for data for each field and link into key tree */

		i = 0;
		while (i < NumFields)
		{

			/* Get the name of the field and its type */

			f_sprintf( (char *)FieldName, "FIELD %u", (unsigned)pIfd->uiFldNum);
			switch( IFD_GET_FIELD_TYPE( pIfd))
			{
				case FLM_TEXT_TYPE:
					f_strcpy( (char *)FieldType, "TEXT");
					break;
				case FLM_NUMBER_TYPE:
					f_strcpy( (char *)FieldType, "NUMBER");
					break;
				case FLM_BINARY_TYPE:
					f_strcpy( (char *)FieldType, "BINARY");
					break;
				case FLM_CONTEXT_TYPE:
					f_strcpy( (char *)FieldType, "CONTEXT");
					break;
				default:
					f_sprintf( (char *)FieldType, "UNK: %u!",
						(unsigned)IFD_GET_FIELD_TYPE( pIfd));
					break;
			}
			if (pIfd->uiFlags & IFD_OPTIONAL)
				f_sprintf( (char *)Prompt, "%s (%s-OPTIONAL): ", FieldName, FieldType);
			else
				f_sprintf( (char *)Prompt, "%s (%s-REQUIRED): ", FieldName, FieldType);

			switch( IFD_GET_FIELD_TYPE( pIfd))
			{
				case FLM_TEXT_TYPE:
					if (!ViewEditText( Prompt, TempBuf, sizeof( TempBuf),
								&ValEntered))
						goto Exit_False;
					break;
				case FLM_NUMBER_TYPE:
				case FLM_CONTEXT_TYPE:
					if (!ViewGetNum( Prompt, &Num, FALSE, 4, 0xFFFFFFFF,
									&ValEntered))
						goto Exit_False;
					break;
				case FLM_BINARY_TYPE:
					Len = sizeof( TempBuf);
					if (!ViewEditBinary( Prompt, TempBuf, &Len, &ValEntered))
						goto Exit_False;
					break;
			}
			if (!ValEntered)
			{
				i++;
			}
			else
			{
				FLMUINT	uiDataType;

				/* See if the entered data can be converted to the */
				/* correct type */

				uiDataType = IFD_GET_FIELD_TYPE( pIfd);
				if (RC_BAD( rc = pKey->insertLast( 1, pIfd->uiFldNum,
													uiDataType, &pvFld)))
				{
					ViewShowRCError( "creating field", rc);
				}
				else
				{
					switch( IFD_GET_FIELD_TYPE( pIfd))
					{
						case FLM_TEXT_TYPE:
							rc = pKey->setNative( pvFld, TempBuf);
							break;
						case FLM_NUMBER_TYPE:
							rc = pKey->setUINT( pvFld, Num);
							break;
						case FLM_CONTEXT_TYPE:
							rc = pKey->setRecPointer( pvFld, Num);
							break;
						case FLM_BINARY_TYPE:
							rc = pKey->setBinary( pvFld, TempBuf, Len);
							break;
					}
					if (RC_BAD( rc))
					{
						ViewShowRCError( "putting data in field", rc);
					}
				}
				if (RC_OK(rc))
				{
					i++;
					pIfd++;
					KeyEntered = TRUE;
				}
			}
		}

		// If index is on all containers, prompt for container number.

		if (!pIxd->uiContainerNum)
		{
			f_strcpy( Prompt, "CONTAINER: ");
			if (!ViewGetNum( Prompt, &Num, FALSE, sizeof( Num), 0xFFFF,
									&ValEntered))
			{
				goto Exit_False;
			}
			if (ValEntered)
			{
				pKey->setContainerID( Num);
				KeyEntered = TRUE;
			}
		}

		/* Convert the key to binary format */

		if (!KeyEntered)
			goto Exit_False;

		if ((rc = FlmKeyBuild( gv_hViewDb, gv_uiViewSearchLfNum,
									pKey->getContainerID(), pKey, 0,
									gv_ucViewSearchKey, &gv_uiViewSearchKeyLen)) != FERR_OK)
			ViewShowRCError( "building key", rc);
		else
		{
			GetOK = TRUE;
			goto Exit_GetKey;
		}
	}

Exit_False:
	GetOK = FALSE;
Exit_GetKey:
	if (pKey)
	{
		pKey->Release();
	}
	return( GetOK);
}