コード例 #1
0
ファイル: fqstack.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc : Adds a value to the selection criteria of a given cursor.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmCursorAddValue(
	HFCURSOR		hCursor,
	QTYPES		eValType,
	void *		pVal,
	FLMUINT		uiValLen
	)
{
	RCODE			rc = FERR_OK;
	FLMUINT		uiVal;
	void *		pTmpVal = pVal;
	CURSOR *		pCursor = (CURSOR *)hCursor;
	F_Pool		pool;
	FLMBOOL		bPoolInitialized = FALSE;

	if (!pCursor)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}
	
	if (RC_BAD( rc = pCursor->rc))
	{
		goto Exit;
	}

	// If a read operation has already been performed on this query, no
	// selection criteria may be added.
	
	if (pCursor->bOptimized)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}
	
	if (!( pCursor->QTInfo.uiExpecting & FLM_Q_OPERAND))
	{
		rc = RC_SET( FERR_CURSOR_SYNTAX);
		goto Exit;
	}

	switch (eValType)
	{

		// Convert all string types to FLM_TEXT_VALUE 
		//	in order to handle pure unicode coming in.

		case FLM_UNICODE_VAL:
		case FLM_STRING_VAL:
		{
			NODE	node;

			f_memset( &node, 0, sizeof(NODE));

			pool.poolInit( 512);
			bPoolInitialized = TRUE;

			rc = (eValType == FLM_UNICODE_VAL) 
					? GedPutUNICODE( &pool, &node, (FLMUNICODE *) pVal)
					: GedPutNATIVE( &pool, &node, (const char *)pVal);
			if (RC_BAD( rc))
			{
				goto Exit;
			}

			pTmpVal = GedValPtr( &node);
			uiValLen = GedValLen( &node);
			eValType = FLM_TEXT_VAL;
			break;
		}

		case FLM_BOOL_VAL:
			if (!pVal)
			{
				uiVal = FLM_UNK;
			}
			else
			{
				FLMBOOL bTrueFalse = (FLMBOOL)*(FLMBOOL *)pVal;
				uiVal = (bTrueFalse) ? FLM_TRUE : FLM_FALSE;
			}
			pTmpVal = &uiVal;
			eValType = FLM_BOOL_VAL;
			break;

		case FLM_INT32_VAL:
		case FLM_UINT32_VAL:
		case FLM_REC_PTR_VAL:
		case FLM_UINT64_VAL:
		case FLM_INT64_VAL:
		case FLM_TEXT_VAL:
		case FLM_BINARY_VAL:
		
			// pTmpVal is already pointing to pVal, and
			// eValType does not need to be changed.
			
			break;

		default:
			flmAssert( 0);
			rc = RC_SET( FERR_CURSOR_SYNTAX);
			break;
	}

	if (RC_OK( rc = flmCurMakeQNode( &pCursor->QueryPool, eValType, pTmpVal,
									uiValLen, pCursor->QTInfo.uiFlags,
									&(pCursor->QTInfo.pCurAtomNode))))
	{
		if (pCursor->QTInfo.pCurOpNode)
		{
			flmCurLinkLastChild( pCursor->QTInfo.pCurOpNode,
					pCursor->QTInfo.pCurAtomNode);
		}
		pCursor->QTInfo.uiExpecting &= ~FLM_Q_OPERAND;
		pCursor->QTInfo.uiExpecting |= FLM_Q_OPERATOR;
	}

Exit:

	if (pCursor)
	{
		pCursor->rc = rc;
	}

	if (bPoolInitialized)
	{
		pool.poolFree();
	}
	
	return( rc);
}
コード例 #2
0
/****************************************************************************
Desc:	Release the existing cache block and setup and alloc new blk.
****************************************************************************/
RCODE F_BtreeRoot::newCacheBlk(
	FLMUINT			uiCachePos,
	F_BtreeBlk **	ppBlk,
	eDynRSetBlkTypes		eBlkType)
{ 
	RCODE			rc = NE_FLM_OK;
	F_BtreeBlk *	pNewBlk = NULL;

	if (m_CacheBlks[uiCachePos].pBlk)
	{
		if (m_CacheBlks[uiCachePos].pBlk->isDirty())
		{
			if (RC_BAD( rc = writeBlk( uiCachePos)))
			{
				goto Exit;
			}
		}
	}

	if (m_CacheBlks[uiCachePos].pBlk != NULL && 
		 m_CacheBlks[uiCachePos].pBlk->blkType() == eBlkType)
	{

		// If block is of the same type then reset it and use it.

		pNewBlk = m_CacheBlks[uiCachePos].pBlk;
		pNewBlk->reset( eBlkType);
		*ppBlk = pNewBlk;
		goto Exit;
	}

	if (m_CacheBlks[uiCachePos].pBlk)
	{
		m_CacheBlks[uiCachePos].pBlk->Release();
	}
	if (eBlkType == ACCESS_BTREE_LEAF)
	{
		F_BtreeLeaf * pLeafBlk;
		if ((pLeafBlk = f_new F_BtreeLeaf) == NULL)
		{
			rc = RC_SET( NE_FLM_MEM);
			goto Exit;
		}
		if (RC_BAD( rc = pLeafBlk->setup( m_uiEntrySize)))
		{
			pLeafBlk->Release();
			goto Exit;
		}
		pLeafBlk->setCompareFunc( m_fnCompare, m_pvUserData);
		pNewBlk = (F_BtreeBlk *) pLeafBlk;
	}
	else
	{
		F_BtreeNonLeaf * pNonLeafBlk;
		if ((pNonLeafBlk = f_new F_BtreeNonLeaf) == NULL)
		{
			rc = RC_SET( NE_FLM_MEM);
			goto Exit;
		}
		if (RC_BAD( rc = pNonLeafBlk->setup( m_uiEntrySize)))
		{
			pNonLeafBlk->Release();
			goto Exit;
		}
		pNonLeafBlk->setCompareFunc( m_fnCompare, m_pvUserData);
		pNewBlk = (F_BtreeBlk *) pNonLeafBlk;
	}
	m_CacheBlks[uiCachePos].pBlk = pNewBlk;
	*ppBlk = pNewBlk;

Exit:

	return( rc);
}
コード例 #3
0
/****************************************************************************
Desc:
****************************************************************************/
JNIEXPORT jlong JNICALL Java_xflaim_Backup__1backup(
	JNIEnv *			pEnv,
	jobject,			// obj,
	jlong				lThis,
	jstring			sBackupPath,
	jstring			sPassword,
	jobject			backupClient,
	jobject			backupStatus)
{
	RCODE						rc = NE_XFLM_OK;
	IF_Backup *				pBackup = THIS_BACKUP();
	FLMUINT					uiSeqNum = 0;
	JavaVM *					pJvm;
	JNIBackupClient *		pClient = NULL;
	JNIBackupStatus *		pStatus = NULL;
	FLMBYTE					ucBackupPath [F_PATH_MAX_SIZE];
	F_DynaBuf				backupPathBuf( ucBackupPath, sizeof( ucBackupPath));
	FLMBYTE					ucPassword [100];
	F_DynaBuf				passwordBuf( ucPassword, sizeof( ucPassword));
	
	if (RC_BAD( rc = getUTF8String( pEnv, sBackupPath, &backupPathBuf)))
	{
		ThrowError( rc, pEnv);
		goto Exit;
	}
	if (RC_BAD( rc = getUTF8String( pEnv, sPassword, &passwordBuf)))
	{
		ThrowError( rc, pEnv);
		goto Exit;
	}
	
	flmAssert( backupClient);
	
	pEnv->GetJavaVM( &pJvm);
	if( (pClient = f_new JNIBackupClient( backupClient, pJvm)) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		ThrowError( rc, pEnv);
		goto Exit;
	}
	
	if (backupStatus)
	{
		if( (pStatus = f_new JNIBackupStatus( backupStatus, pJvm)) == NULL)
		{
			rc = RC_SET( NE_XFLM_MEM);
			ThrowError( rc, pEnv);
			goto Exit;
		}
	}
	
	if (RC_BAD( rc = pBackup->backup(
							(const char *)(backupPathBuf.getDataLength() > 1
											   ? (const char *)backupPathBuf.getBufferPtr()
												: (const char *)NULL),
							(const char *)(passwordBuf.getDataLength() > 1
											   ? (const char *)passwordBuf.getBufferPtr()
												: (const char *)NULL),
							pClient, pStatus, &uiSeqNum)))
	{
		ThrowError( rc, pEnv);
		goto Exit;
	}
	
Exit:

	if (pClient)
	{
		pClient->Release();
	}
	
	if (pStatus)
	{
		pStatus->Release();
	}
	
	return( uiSeqNum);
}
コード例 #4
0
/****************************************************************************
 Desc:	Searches the SCache for the block referenced by the parameters.  If
			found, it copies the data into pLocalSCache.  Assumes that the 
			mutex has already been locked!
****************************************************************************/
RCODE F_SCacheBase::locateSCacheBlock(
	FLMUINT			uiNumParams,
	const char **	ppszParams,
	SCACHE *			pLocalSCache,
	FLMUINT *		puiBlkAddress,
	FLMUINT *		puiLowTransID,
	FLMUINT *		puiHighTransID,
	FFILE * *		ppFile)
{
	RCODE				rc = FERR_OK;

	FLMUINT			uiSigBitsInBlkSize;
	SCACHE *			pSCache;
	SCACHE **		ppSCache;
#define MAXPARAMLEN 15
	char				szBlkAddress[MAXPARAMLEN];
	char				szLowTransID[MAXPARAMLEN];
	char				szHighTransID[MAXPARAMLEN];
	char				szFile[MAXPARAMLEN];

	// Grab the block address, low and high trans id's and FFile pointer, which
	// we need to uniquely identify an scache block...
	
	if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams,
												  "BlockAddress", sizeof( szBlkAddress),
												  &szBlkAddress[0])))
	{  
		goto Exit;
	}
	*puiBlkAddress = f_atoi( szBlkAddress);

	if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams,
												  "LowTransID", sizeof( szLowTransID),
												  &szLowTransID[0])))
	{
		goto Exit;
	}
	*puiLowTransID = f_atoi( szLowTransID);

	if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams,
												  "HighTransID", sizeof( szHighTransID),
												  &szHighTransID[0])))
	{
		goto Exit;
	}
	*puiHighTransID = f_atoi( szHighTransID);

	if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, 
												  "File", sizeof( szFile),
												  &szFile[0])))
	{ 
		goto Exit;
	}
	*ppFile = (FFILE *)f_atoud( szFile);

	flmAssert( *ppFile);
	uiSigBitsInBlkSize = (*ppFile)->FileHdr.uiSigBitsInBlkSize;

	// ScaHash actually returns a pointer to the first scache in the hash
	// bucket. It's up to us to traverse this list to find the proper block
	// address and FFile (and potentially high and low trans id)
	ppSCache = ScaHash( uiSigBitsInBlkSize,	*puiBlkAddress);
	pSCache = *ppSCache;

	while (	pSCache &&
				(	(pSCache->uiBlkAddress != *puiBlkAddress)	||
					(pSCache->pFile != *ppFile) )					)
	{
		pSCache = pSCache->pNextInHashBucket;
	}

	// Ok - we've found the right address and ffile.  Do we need a different
	// version?
	while (	(pSCache)	&&
				(pSCache->uiHighTransID != *puiHighTransID)	&&
				(scaGetLowTransID( pSCache) != *puiLowTransID) )
	{
		pSCache = pSCache->pNextInVersionList;
	}


	// Now, if we've found the right block, copy it's contents to local memory...
	if (pSCache)
	{
		f_memcpy( pLocalSCache, pSCache, sizeof( SCACHE));
	}
	else
	{
		rc = RC_SET( FERR_NOT_FOUND);
		goto Exit;
	}

Exit:
	return( rc);
}
コード例 #5
0
/****************************************************************************
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);
}
コード例 #6
0
/****************************************************************************
Desc : Checks for physical corruption in a FLAIM database.
DNote: The routine verifies the database by first reading through
		 the database to count certain block types which are in linked lists.
		 It then verifies the linked lists.  It also verifies the B-TREEs
		 in the database.  The reason for the first pass is so that when we
		 verify the linked lists, we can keep ourselves from getting into
		 an infinite loop if there is a loop in the lists.
****************************************************************************/
RCODE F_DbCheck::dbCheck(
	const char *		pszDbFileName,
		// [IN] Full path and file name of the database which
		// is to be checked.  NULL can be passed as the value of
		// this parameter if pDb is non-NULL.
	const char *		pszDataDir,
		// [IN] Directory for data files.
	const char *		pszRflDir,
		// [IN] RFL directory.  NULL can be passed as the value of
		// this parameter to indicate that the log files are located
		// in the same directory as the database or if pDb is non-NULL.
	const char *		pszPassword,
		// [IN] Database password. Needed to open the database if the database
		// key has been wrapped in a password. NULL by default.
	FLMUINT				uiFlags,
		// [IN] Check flags.  Possible flags include:
		//
		//		XFLM_ONLINE. This flag instructs the check to repair any
		//		index corruptions it finds.  The database must have been
		//		opened in read/write mode in order for the check to
		//		successfully repair corruptions.  An update transaction
		//		will be started whenever a corruption is repaired.
		//
		//		XFLM_DO_LOGICAL_CHECK.  This flag instructs the check to
		//		perform a logical check of the databases's indexes
		//		in addition to the structural check.
		//
		//		XFLM_SKIP_DOM_LINK_CHECK.  This flag instructs the check to skip
		//		verifying the DOM links.  This check can take quite a long time
		//		to execute.
		//
		//		XFLM_ALLOW_LIMITED_MODE. This flag instructs the check to allow
		//		the database to be opened in limited mode if the database key is
		//		wrapped in a password and the password we pass is	incorrect 
		//		(or non-existent).
	IF_DbInfo **			ppDbInfo,
		// [IN] Pointer to a DB_INFO structure which is used to store
		// statistics collected during the database check.
	IF_DbCheckStatus *	pDbCheckStatus
		// [IN] Status interface.  Functions in this interface are called 
		// periodically to iform the calling application of the progress
		// being made.  This allows the application to monitor and/or display
		// the progress of the database check.  NULL may be passed as the
		// value of this parameter if the callback feature is not needed.
	)
{
	RCODE								rc = NE_XFLM_OK;
	FLMBYTE *						pBlk = NULL;
	FLMUINT							uiFileEnd;
	FLMUINT							uiBlockSize;
	FLMUINT							uiLoop;
	FLMUINT64						ui64TmpSize;
	FLMBOOL							bStartOver;
	FLMBOOL							bOkToCloseTrans = FALSE;
	FLMBOOL							bAllowLimitedMode =  ( uiFlags & XFLM_ALLOW_LIMITED_MODE)
																		? TRUE
																		: FALSE;

	if (RC_BAD( rc = gv_pXFlmDbSystem->dbOpen( pszDbFileName, pszDataDir,
		pszRflDir, pszPassword, bAllowLimitedMode, (IF_Db **)&m_pDb)))
	{
		goto Exit;
	}

	if ((m_pDbInfo = f_new F_DbInfo) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}
	if (ppDbInfo)
	{
		*ppDbInfo = m_pDbInfo;
		(*ppDbInfo)->AddRef();
	}

	m_pDbCheckStatus = pDbCheckStatus;
	m_LastStatusRc = NE_XFLM_OK;

	// Get the file size...

	if (uiFlags & XFLM_SKIP_DOM_LINK_CHECK)
	{
		m_bSkipDOMLinkCheck = TRUE;
	}

	// Initialize the information block and Progress structure.

	// Since we know that the check will start read transactions
	// during its processing, set the flag to indicate that the KRef table
	// should be cleaned up on exit if we are still in a read transaction.

	bOkToCloseTrans = TRUE;
	uiBlockSize = m_pDb->m_pDatabase->getBlockSize();

	// Allocate memory to use for reading through the data blocks.

	if( RC_BAD( rc = f_alloc( uiBlockSize, &pBlk)))
	{
		goto Exit;
	}

	if ((m_pBtPool = f_new F_BtPool) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}

	if (RC_BAD( rc = m_pBtPool->btpInit()))
	{
		goto Exit;
	}
	
	// Setup the result set database.
	
	if( RC_BAD( rc = FlmAllocRandomGenerator( &m_pRandGen)))
	{
		goto Exit;
	}

	m_pRandGen->setSeed( 9768);

	if (RC_BAD( rc = createAndOpenResultSetDb()))
	{
		goto Exit;
	}

Begin_Check:

	// Initialize all statistics in the DB_INFO structure.

	rc = NE_XFLM_OK;
	bStartOver = FALSE;

	m_pDbInfo->m_ui64FileSize = 0;
	m_pDbInfo->freeLogicalFiles();
	m_bPhysicalCorrupt = FALSE;
	m_bIndexCorrupt = FALSE;
	m_uiFlags = uiFlags;
	m_bStartedUpdateTrans = FALSE;
	f_memset( &m_pDbInfo->m_AvailBlocks, 0, sizeof( BLOCK_INFO));
	f_memset( &m_pDbInfo->m_LFHBlocks, 0, sizeof( BLOCK_INFO));

	f_memset( &m_Progress, 0, sizeof( XFLM_PROGRESS_CHECK_INFO));

	/* Get the dictionary information for the file. */

	if (RC_BAD( rc = getDictInfo()))
	{
		goto Exit;
	}

	m_Progress.ui64BytesExamined = 0;

	for (uiLoop = 1;
		  uiLoop <= MAX_DATA_BLOCK_FILE_NUMBER;
		  uiLoop++)
	{
		if (RC_BAD( m_pDb->m_pSFileHdl->getFileSize( uiLoop, &ui64TmpSize)))
		{
			break;
		}
		
		m_Progress.ui64FileSize += ui64TmpSize;
	}

	// See if we have a valid end of file

	uiFileEnd = m_pDb->m_uiLogicalEOF;
	if (FSGetFileOffset( uiFileEnd) % uiBlockSize != 0)
	{
		if (RC_BAD( rc = chkReportError( FLM_BAD_FILE_SIZE, XFLM_LOCALE_NONE,
			0, 0, 0xFF, (FLMUINT32)uiFileEnd, 0, 0, 0)))
		{
			goto Exit;
		}
	}
	else if (m_Progress.ui64FileSize <
					FSGetSizeInBytes( m_pDb->m_pDatabase-> getMaxFileSize(),
																		uiFileEnd))
	{
		m_Progress.ui64FileSize =
					FSGetSizeInBytes( m_pDb->m_pDatabase->getMaxFileSize(),
																uiFileEnd);
	}

	m_pDbInfo->m_ui64FileSize = m_Progress.ui64FileSize;

	// Verify the LFH blocks, B-Trees, and the AVAIL list.

	if( RC_BAD( rc = verifyLFHBlocks( &bStartOver)))
	{
		goto Exit;
	}
	if (bStartOver)
	{
		goto Begin_Check;
	}

	// Check the b-trees.
	
	if (RC_BAD( rc = verifyBTrees( &bStartOver)))
	{
		goto Exit;
	}
	if (bStartOver)
	{
		goto Begin_Check;
	}

	// Check the avail list.

	if (RC_BAD( rc = verifyAvailList( &bStartOver)))
	{
		goto Exit;
	}
	if (bStartOver)
	{
		goto Begin_Check;
	}

Exit:

	if ((m_bPhysicalCorrupt || m_bIndexCorrupt) &&
		 !gv_pXFlmDbSystem->errorIsFileCorrupt( rc))
	{
		rc = RC_SET( NE_XFLM_DATA_ERROR);
	}

	if (RC_OK( rc) && RC_BAD( m_LastStatusRc))
	{
		rc = m_LastStatusRc;
	}

	if (m_pDb)
	{
		// Close down the transaction, if one is going

		if( bOkToCloseTrans &&
			m_pDb->getTransType( ) == XFLM_READ_TRANS)
		{
			m_pDb->krefCntrlFree();
			m_pDb->transAbort();
		}
	}
	
	// Free memory, if allocated

	if (pBlk)
	{
		f_free( &pBlk);
	}

	// Close the FLAIM database we opened.

	if (m_pDb)
	{
		m_pDb->Release();
		m_pDb = NULL;
	}

	return( rc);
}
コード例 #7
0
/****************************************************************************
Desc:	Checks for physical corruption in a FLAIM database.
Note:	The routine verifies the database by first reading through
		the database to count certain block types which are in linked lists.
		It then verifies the linked lists.  It also verifies the B-TREEs
		in the database.  The reason for the first pass is so that when we
		verify the linked lists, we can keep ourselves from getting into
		an infinite loop if there is a loop in the lists.
****************************************************************************/
RCODE XFLAPI F_DbSystem::dbCheck(
	const char *			pszDbFileName,
		// [IN] Full path and file name of the database which
		// is to be checked.  NULL can be passed as the value of
		// this parameter if pDb is non-NULL.
	const char *			pszDataDir,
		// [IN] Directory for data files.
	const char *			pszRflDir,
		// [IN] RFL directory.  NULL can be passed as the value of
		// this parameter to indicate that the log files are located
		// in the same directory as the database or if pDb is non-NULL.
	const char *			pszPassword,
		// [IN] Database password. This is necessary to open the database if
		// the key has been wrapped in a password. NULL by default.
	FLMUINT					uiFlags,
		// [IN] Check flags.  Possible flags include:
		//
		//		XFLM_ONLINE. This flag instructs the check to repair any
		//		index corruptions it finds.  The database must have been
		//		opened in read/write mode in order for the check to
		//		successfully repair corruptions.  An update transaction
		//		will be started whenever a corruption is repaired.
		//
		//		XFLM_DO_LOGICAL_CHECK.  This flag instructs the check to
		//		perform a logical check of the databases's indexes
		//		in addition to the structural check.
		//
		//		XFLM_SKIP_DOM_LINK_CHECK.  This flag instructs the check to skip
		//		verifying the DOM links.  This check can take quite a long time
		//		to execute.
		//
		//		XFLM_ALLOW_LIMITED_MODE. This flag instructs the check to allow
		//		the database to be opened in limited mode if the database key is
		//		wrapped in a password and the password we pass is	incorrect 
		//		(or non-existent).
	IF_DbInfo **			ppDbInfo,
		// [IN] Pointer to a DB_INFO structure which is used to store
		// statistics collected during the database check.
	IF_DbCheckStatus *	pDbCheckStatus
		// [IN] Status interface.  Functions in this interface are called 
		// periodically to iform the calling application of the progress
		// being made.  This allows the application to monitor and/or display
		// the progress of the database check.  NULL may be passed as the
		// value of this parameter if the callback feature is not needed.
	)
{
	RCODE			rc = NE_XFLM_OK;
	F_DbCheck *	pCheckObj = NULL;

	if ((pCheckObj = f_new F_DbCheck) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}

	rc = pCheckObj->dbCheck( pszDbFileName, pszDataDir, pszRflDir, pszPassword,
		uiFlags, ppDbInfo, pDbCheckStatus);

Exit:

	if (pCheckObj)
	{
		pCheckObj->Release();
	}
	return( rc);
}
コード例 #8
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	Starts a transaction.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmDbTransBegin(
	HFDB			hDb,
	FLMUINT		uiTransType,
	FLMUINT		uiMaxLockWait,
	FLMBYTE *	pucHeader)
{
	RCODE			rc = FERR_OK;
	FLMBOOL		bIgnore;
	FLMUINT		uiFlags = FLM_GET_TRANS_FLAGS( uiTransType);
	FDB *			pDb = (FDB *)hDb;

	uiTransType = FLM_GET_TRANS_TYPE( uiTransType);

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		FCL_WIRE		Wire( pDb->pCSContext, pDb);

		if (!pDb->pCSContext->bConnectionGood)
		{
			rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
		}
		else
		{
			if( RC_BAD( rc = Wire.doTransOp(
				FCS_OP_TRANSACTION_BEGIN, uiTransType, uiFlags,
				uiMaxLockWait, pucHeader)))
			{
				goto Exit;
			}
		}

		goto Exit;
	}

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

	// Verify the transaction type.

	if (( uiTransType != FLM_UPDATE_TRANS) &&
		 ( uiTransType != FLM_READ_TRANS))
	{
		rc = RC_SET( FERR_ILLEGAL_TRANS);
		goto Exit;
	}

	// Verify the transaction flags

	if( (uiFlags & FLM_DONT_KILL_TRANS) && uiTransType != FLM_READ_TRANS)
	{
		rc = RC_SET( FERR_ILLEGAL_TRANS);
		goto Exit;
	}

	// Can't start an update transaction on a database that
	// is locked in shared mode.

	if ((uiTransType == FLM_UPDATE_TRANS) &&
		 (pDb->uiFlags & FDB_FILE_LOCK_SHARED))
	{
		rc = RC_SET( FERR_PERMISSION);
		goto Exit;
	}

	// If the database has an invisible transaction going, abort it
	// before going any further - we don't want application transactions
	// to be nested under invisible transactions.  Application transactions
	// take precedence over invisible transactions.

	if ((pDb->uiTransType != FLM_NO_TRANS) &&
		 (pDb->uiFlags & FDB_INVISIBLE_TRANS))
	{
		if (RC_BAD( rc = flmAbortDbTrans( pDb)))
		{
			goto Exit;
		}
	}

	// If the database is not running a transaction, start one.
	// Otherwise, start a nested transaction - first verifying that
	// the transation type matches.

	if (pDb->uiTransType == FLM_NO_TRANS)
	{
		FLMUINT		uiBytesRead;

		if( pucHeader)
		{
			if( RC_BAD( rc = pDb->pSFileHdl->readBlock( 
				0, 2048, pucHeader, &uiBytesRead)))
			{
				goto Exit;
			}
		}

		if (RC_BAD( rc = flmBeginDbTrans( pDb, uiTransType, 
			uiMaxLockWait, uiFlags,
			pucHeader ? &pucHeader [16] : NULL)))
		{
			goto Exit;
		}
		pDb->bHadUpdOper = FALSE;
	}
	else
	{
		// Cannot nest transactions.

		rc = RC_SET( FERR_TRANS_ACTIVE);
		goto Exit;
	}

Exit:

	flmExit( FLM_DB_TRANS_BEGIN, pDb, rc);
	return( rc);
}
コード例 #9
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
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);
}
コード例 #10
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	Commits an active transaction.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmDbTransCommit(
	HFDB			hDb,
	FLMBOOL *	pbEmpty)
{
	RCODE			rc = FERR_OK;
	FDB *			pDb = (FDB *)hDb;
	FLMBOOL		bIgnore;

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		FCL_WIRE		Wire( pDb->pCSContext, pDb);

		if (!pDb->pCSContext->bConnectionGood)
		{
			rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
		}
		else
		{
			rc = Wire.doTransOp(	FCS_OP_TRANSACTION_COMMIT, 0, 0, 0);
		}
		goto Exit;
	}

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

	// If there is an invisible transaction going, it should not be
	// commitable by an application.

	if ((pDb->uiTransType == FLM_NO_TRANS) ||
		 (pDb->uiFlags & FDB_INVISIBLE_TRANS))
	{
		rc = RC_SET( FERR_NO_TRANS_ACTIVE);
		goto Exit;
	}

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

	if( RC_BAD( pDb->AbortRc))
	{
		rc = RC_SET( FERR_ABORT_TRANS);
		goto Exit;
	}

	if (pbEmpty)
	{
		*pbEmpty = FALSE;
	}
	rc = flmCommitDbTrans( pDb, 0, FALSE, pbEmpty);

Exit:

	if( RC_OK( rc))
	{
		rc = flmCheckDatabaseState( pDb);
	}

	flmExit( FLM_DB_TRANS_COMMIT, pDb, rc);
	return( rc);
}
コード例 #11
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc : Returns the type of the current database transaction.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmDbGetTransType(
	HFDB			hDb,
	FLMUINT *	puiTransTypeRV)
{
	RCODE		   rc = FERR_OK;
	FDB *			pDb = (FDB *)hDb;

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

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

		// Send a request to get the transaction type.

		if( RC_BAD( rc = Wire.sendOp( 
			FCS_OPCLASS_TRANS, FCS_OP_TRANSACTION_GET_TYPE)))
		{
			goto Exit;
		}

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

		// Read the response.
	
		if (RC_BAD( rc = Wire.read()))
		{
			goto Transmission_Error;
		}
		
		*puiTransTypeRV = Wire.getTransType();
		rc = Wire.getRCode();
		goto Exit;

Transmission_Error:

		pCSContext->bConnectionGood = FALSE;
		goto Exit;
	}

	if (!pDb)
	{
		rc = RC_SET( FERR_BAD_HDL);
		goto Exit;
	}

	fdbUseCheck( pDb);
	pDb->uiInitNestLevel++;
	(void)flmResetDiag( pDb);

	// If the transaction is an internal transaction that is invisible to
	// the application, return FLM_NO_TRANS.  Application is not supposed
	// see invisible transactions.

	*puiTransTypeRV = (FLMUINT)(((pDb->uiTransType == FLM_NO_TRANS) ||
										  (pDb->uiFlags & FDB_INVISIBLE_TRANS))
										  			? (FLMUINT)FLM_NO_TRANS
													: pDb->uiTransType);

	// See if the database is being forced to close

	if( RC_BAD( rc = flmCheckDatabaseState( pDb)))
	{
		goto Exit;
	}

Exit:

	flmExit( FLM_DB_GET_TRANS_TYPE, pDb, rc);
	return( rc);
}
コード例 #12
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	This routine commits an active transaction for a particular
		database.  If the database is open via a server, a message is
		sent to the server to commit the transaction.  Otherwise, the
		transaction is committed locally.
****************************************************************************/
RCODE flmCommitDbTrans(
	FDB *				pDb,
	FLMUINT			uiNewLogicalEOF,
	FLMBOOL			bForceCheckpoint,
	FLMBOOL *		pbEmpty)
{
	RCODE	  			rc = FERR_OK;
	FLMBYTE *		pucUncommittedLogHdr;
	FFILE *			pFile = pDb->pFile;
	FLMUINT			uiCPFileNum = 0;
	FLMUINT			uiCPOffset = 0;
	FLMUINT			uiTransId = 0;
	FLMBOOL			bTransEndLogged;
	FLMBOOL			bForceCloseOnError = FALSE;
	FLMBOOL			bOkToLogAbort = TRUE;
	DB_STATS *		pDbStats = pDb->pDbStats;
	FLMUINT			uiTransType;
	FLMBOOL			bInvisibleTrans = FALSE;
	FLMBOOL			bIndexAfterCommit = FALSE;

	pDb->uiFlags |= FDB_COMMITTING_TRANS;

	// See if we even have a transaction going.

	if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS)
	{
		goto Exit;	// Will return FERR_OK.
	}

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

	if (flmCheckBadTrans( pDb))
	{
		rc = RC_SET( FERR_ABORT_TRANS);
		goto Exit;
	}

	// If we are in a read transaction we can skip most of the stuff
	// below because no updates would have occurred.  This will help
	// improve performance.

	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 Exit1;
	}

	// At this point, we know we have an update transaction.

	pFile->pRfl->clearLogHdrs();

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

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

	if (!pDb->bHadUpdOper)
	{
		bOkToLogAbort = FALSE;
		rc = pFile->pRfl->logEndTransaction( RFL_TRNS_COMMIT_PACKET, TRUE);

		// Even though we didn't have any update operations, there may have
		// been operations during the transaction (i.e., query operations)
		// that initialized the KREF in order to generate keys.

		KrefCntrlFree( pDb);

		// Restore everything as if the transaction never happened.

		f_mutexLock( gv_FlmSysData.hShareMutex);
		pFile->uiUpdateTransID = 0;
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
		if (pbEmpty)
		{
			*pbEmpty = TRUE;
		}
		goto Exit1;
	}

	// Log commit record to roll-forward log

	bOkToLogAbort = FALSE;
	if (RC_BAD( rc = pFile->pRfl->logEndTransaction(
								RFL_TRNS_COMMIT_PACKET, FALSE, &bTransEndLogged)))
	{
		goto Exit1;
	}
	bForceCloseOnError = TRUE;

	// Commit any keys in the KREF buffers.

	if (RC_BAD( rc = KYKeysCommit( pDb, TRUE)))
	{
		flmLogError( rc, "calling KYKeysCommit from flmCommitDbTrans");
		goto Exit1;
	}

	if (RC_BAD( rc = FSCommitIxCounts( pDb)))
	{
		flmLogError( rc, "calling FSCommitIxCounts from flmCommitDbTrans");
		goto Exit1;
	}

	// Reinitialize the log header.  If the local dictionary was updated
	// during the transaction, increment the local dictionary ID so that
	// other concurrent users will know that it has been modified and
	// that they need to re-read it into memory.

	// If we are in recovery mode, see if we need to force
	// a checkpoint with what we have so far.  We force a
	// checkpoint on one of two conditions:
	
	// 1. If it appears that we have a buildup of dirty cache
	//		blocks.  We force a checkpoint on this condition
	//		because it will be more efficient than replacing
	//		cache blocks one at a time.
	//		We check for this condition by looking to see if
	//		our LRU block is not used and it is dirty.  That is
	//		a pretty good indicator that we have a buildup
	//		of dirty cache blocks.
	// 2.	We are at the end of the roll-forward log.  We
	//		want to force a checkpoint here to complete the
	//		recovery phase.

	if ( pDb->uiFlags & FDB_REPLAYING_RFL)
	{
		// If we are in the middle of upgrading, and are forcing
		// a checkpoint, use the file number and offset that were
		// set in the FDB.

		if ((pDb->uiFlags & FDB_UPGRADING) && bForceCheckpoint)
		{
			uiCPFileNum = pDb->uiUpgradeCPFileNum;
			uiCPOffset = pDb->uiUpgradeCPOffset;
		}
		else
		{
			SCACHE *		pTmpSCache;
			F_Rfl *		pRfl = pFile->pRfl;

			f_mutexLock( gv_FlmSysData.hShareMutex);
			pTmpSCache = gv_FlmSysData.SCacheMgr.pLRUCache;

			// Test for buildup of dirty cache blocks.

			if( (pTmpSCache && !pTmpSCache->uiUseCount &&
				  (pTmpSCache->ui16Flags & 
						(CA_DIRTY | CA_LOG_FOR_CP | CA_WRITE_TO_LOG))) ||
				pRfl->atEndOfLog() || bForceCheckpoint)
			{
				bForceCheckpoint = TRUE;
				uiCPFileNum = pRfl->getCurrFileNum();
				uiCPOffset = pRfl->getCurrReadOffset();
			}
			
			f_mutexUnlock( gv_FlmSysData.hShareMutex);
		}
	}

	// Move information collected in the pDb->LogHdr into the
	// uncommitted log header.  Other things that need to be
	// set have already been set in the uncommitted log header
	// at various places in the code.

	// Mutex does not have to be locked while we do this because
	// the update transaction is the only one that ever accesses
	// the uncommitted log header buffer.

	pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0];

	// Set the new logical EOF if passed in.

	if( uiNewLogicalEOF)
	{
		pDb->LogHdr.uiLogicalEOF = uiNewLogicalEOF;
	}
	
	UD2FBA( (FLMUINT32)pDb->LogHdr.uiLogicalEOF,
		&pucUncommittedLogHdr [LOG_LOGICAL_EOF]);

	// Increment the commit counter.

	flmIncrUint( &pucUncommittedLogHdr [LOG_COMMIT_COUNT], 1);

	// Set the last committed transaction ID

	if( (bTransEndLogged || (pDb->uiFlags & FDB_REPLAYING_COMMIT)) &&
		pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_31)
	{
		UD2FBA( (FLMUINT32)uiTransId, 
			&pucUncommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]);
	}

	// Write the header

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

	// Commit any record cache.

	flmRcaCommitTrans( pDb);

	// Push the IXD_FIXUP values back into the IXD

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

		pIxdFixup = pDb->pIxdFixups;
		while (pIxdFixup)
		{
			if( RC_BAD( fdictGetIndex(
				pDb->pDict, pDb->pFile->bInLimitedMode,
				pIxdFixup->uiIndexNum, NULL, &pIxd, TRUE)))
			{
				flmAssert( 0);
				pIxd = NULL;
			}

			if( pIxd)
			{
				pIxd->uiLastContainerIndexed = pIxdFixup->uiLastContainerIndexed;
				pIxd->uiLastDrnIndexed = pIxdFixup->uiLastDrnIndexed;
			}
			pDeleteIxdFixup = pIxdFixup;
			pIxdFixup = pIxdFixup->pNext;
			f_free( &pDeleteIxdFixup);
		}
		pDb->pIxdFixups = NULL;
	}

	// Set the update transaction ID back to zero only 
	// AFTER we know the transaction has safely committed.

	f_mutexLock( gv_FlmSysData.hShareMutex);
	f_memcpy( pFile->ucLastCommittedLogHdr, pucUncommittedLogHdr,
					LOG_HEADER_SIZE);
	pFile->uiUpdateTransID = 0;
	ScaReleaseLogBlocks( pFile);
	if (pDb->uiFlags & FDB_UPDATED_DICTIONARY)
	{
		// Link the new local dictionary to its file.
		// Since the new local dictionary will be linked at the head
		// of the list of FDICT structures, see if the FDICT currently
		// at the head of the list is unused and can be unlinked.

		if ((pFile->pDictList) && (!pFile->pDictList->uiUseCount))
		{
			flmUnlinkDict( pFile->pDictList);
		}
		flmLinkDictToFile( pFile, pDb->pDict);
	}

	f_mutexUnlock( gv_FlmSysData.hShareMutex);

Exit1:

	// If the local dictionary was updated during this transaction,
	// link the new local dictionary structures to their file - or free
	// them if there was an error.

	if (pDb->uiFlags & FDB_UPDATED_DICTIONARY)
	{
		if( RC_BAD( rc) && pDb->pDict)
		{
			// Unlink the FDB from the FDICT. - Shouldn't have
			// to lock semaphore, because the DICT is NOT linked
			// to the FFILE.

			flmAssert( pDb->pDict->pFile == NULL);
			flmUnlinkFdbFromDict( pDb);
		}
	}

	if (RC_BAD( rc))
	{

		// Since we failed to commit, do an abort.  We are purposely not
		// checking the return code from flmAbortDbTrans because we already
		// have an error return code.  If we attempted to log the transaction
		// to the RFL and failed, we don't want to try to log an abort packet.
		// The RFL code has already reset the log back to the starting point 
		// of the transaction, thereby discarding all operations.

		pDb->uiFlags &= ~FDB_COMMITTING_TRANS;
		(void)flmAbortDbTrans( pDb, bOkToLogAbort);
		uiTransType = FLM_NO_TRANS;

		// Do we need to force all handles to close?

		if( bForceCloseOnError)
		{

			// Since the commit packet has already been logged to the RFL,
			// we must have failed when trying to write the log header.  The
			// database is in a bad state and must be closed.

			// Set the "must close" flag on all FDBs linked to the FFILE
			// and set the FFILE's "must close" flag.  This will cause any
			// subsequent operations on the database to fail until all
			// handles have been closed.

			flmSetMustCloseFlags( pFile, rc, FALSE);
		}
	}
	else
	{
		bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE;
		if (uiTransType == FLM_UPDATE_TRANS)
		{
			if (gv_FlmSysData.UpdateEvents.pEventCBList)
			{
				flmTransEventCallback( F_EVENT_COMMIT_TRANS, (HFDB)pDb, rc,
							uiTransId);
			}

			// Do the BLOB and indexing work before we unlock the db.

			FBListAfterCommit( pDb);
			
			if (pDb->pIxStopList || pDb->pIxStartList)
			{
				
				// Must not call flmIndexingAfterCommit until after
				// completeTransWrites.  Otherwise, there is a potential
				// deadlock condition where flmIndexingAfterCommit is
				// waiting on an indexing thread to quit, but that
				// thread is waiting to be signaled by this thread that
				// writes are completed.  However, flmIndexingAfterCommit
				// also must only be called while the database is still
				// locked.  If we were to leave the database locked for
				// every call to completeTransWrites, however, we would
				// lose the group commit capability.  Hence, we opt to
				// only lose it when there are actual indexing operations
				// to start or stop - which should be very few transactions.
				// That is what the bIndexAfterCommit flag is for.
				
				bIndexAfterCommit = TRUE;
			}
		}
	}

	// Unlock the database, if the update transaction is still going.
	// NOTE: We check uiTransType because it may have been reset
	// to FLM_NO_TRANS up above if flmAbortDbTrans was called.

	if (uiTransType == FLM_UPDATE_TRANS)
	{
		if (RC_BAD( rc))
		{

			// SHOULD NEVER HAPPEN - because it would have been taken
			// care of above - flmAbortDbTrans would have been called and
			// uiTransType would no longer be FLM_UPDATE_TRANS.

			flmAssert( 0);
			(void)pFile->pRfl->completeTransWrites( pDb, FALSE, TRUE);
		}
		else if( !bForceCheckpoint)
		{
			if( bIndexAfterCommit)
			{
				rc = pFile->pRfl->completeTransWrites( pDb, TRUE, FALSE);
				flmIndexingAfterCommit( pDb);
				flmUnlinkDbFromTrans( pDb, TRUE);
			}
			else
			{
				rc = pFile->pRfl->completeTransWrites( pDb, TRUE, TRUE);
			}
		}
		else
		{

			// Do checkpoint, if forcing.  Before doing the checkpoint
			// we have to make sure the roll-forward log writes
			// complete.  We don't want to unlock the DB while the
			// writes are happening in this case - thus, the FALSE
			// parameter to completeTransWrites.

			if (RC_OK( rc = pFile->pRfl->completeTransWrites( pDb, TRUE, FALSE)))
			{
				bForceCloseOnError = FALSE;
				rc = ScaDoCheckpoint( pDbStats, pDb->pSFileHdl, pFile,
						(pDb->uiFlags & FDB_DO_TRUNCATE) ? TRUE : FALSE,
						TRUE, CP_TIME_INTERVAL_REASON,
						uiCPFileNum, uiCPOffset);
			}
			
			if (bIndexAfterCommit)
			{
				flmIndexingAfterCommit( pDb);
			}
			
			flmUnlinkDbFromTrans( pDb, TRUE);
		}

		if (RC_BAD( rc) && bForceCloseOnError)
		{

			// Since the commit packet has already been logged to the RFL,
			// we must have failed when trying to write the log header.  The
			// database is in a bad state and must be closed.

			// Set the "must close" flag on all FDBs linked to the FFILE
			// and set the FFILE's "must close" flag.  This will cause any
			// subsequent operations on the database to fail until all
			// handles have been closed.

			flmSetMustCloseFlags( pFile, rc, FALSE);
		}
	}
	else
	{

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

		flmUnlinkDbFromTrans( pDb, FALSE);
	}

	if (pDbStats && uiTransType != FLM_NO_TRANS)
	{
		FLMUINT64	ui64ElapMilli = 0;

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

	// Update stats

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

Exit:

	pDb->uiFlags &= ~FDB_COMMITTING_TRANS;
	return( rc);
}
コード例 #13
0
/****************************************************************************
Desc:
****************************************************************************/
RCODE	SortKeyTestImpl::verifyQuery( 
	const char *		pszQuery, 
	char*					ppszNames[][ 2],
	IF_Query *			pQuery,
	FLMUINT				uiNumNames,
	FLMBOOL				bFirstAscending,
	FLMBOOL				bLastAscending,
	FLMBOOL				bDocsIndexed,
	FLMBOOL				bIxFirstAscending,
	FLMBOOL				bIxLastAscending)
{
	RCODE					rc = NE_XFLM_OK;
	IF_DOMNode *		pResultNode = NULL;
	IF_DOMNode *		pFirstNameNode = NULL;
	IF_DOMNode *		pLastNameNode = NULL;
	FLMUINT				uiLoop;
	FLMUINT				uiPos;
	char					szBuf[ 100];
	IF_DataVector *	pSearchKey = NULL;
	char					szTestName[ 200];
	static FLMUINT		uiCallCount = 0;
	const char *		pszTestNameFormat = 
		"Verify Query #%u "
		"(%s/First Name Asc == %u/Last Name Asc ==%u/%s)";


	uiCallCount++;

	f_sprintf( szTestName, pszTestNameFormat, uiCallCount,
		pszQuery, (unsigned)bFirstAscending, (unsigned)bLastAscending,
		"positioning");

	beginTest( szTestName, 
		"Ensure queries return proper results in proper order",
		"No Additional Info",
		"");

	// positioning tests

	if ( RC_BAD( rc = pQuery->setupQueryExpr( m_pDb, pszQuery)))
	{
		MAKE_FLM_ERROR_STRING( "setupQueryExpr failed.", m_szDetails, rc);
		goto Exit;
	}

	if ( bDocsIndexed && 
		(bFirstAscending == bIxFirstAscending && 
		bLastAscending == bIxLastAscending))
	{
		pQuery->setIndex( IX_NUM);
	}

	if ( RC_BAD( rc = pQuery->enablePositioning()))
	{
		MAKE_FLM_ERROR_STRING( "enablePositioning failed.", m_szDetails, rc);
		goto Exit;
	}

	if ( RC_BAD( rc = createSortKey( 
		pQuery, bFirstAscending, bLastAscending)))
	{
		goto Exit;
	}

	for( uiLoop = 0; uiLoop < uiNumNames; uiLoop++)
	{

		if ( RC_BAD( rc = pQuery->positionTo( 
			m_pDb, &pResultNode, 0, uiLoop)))
		{
			MAKE_FLM_ERROR_STRING( "positionTo failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pResultNode->getFirstChild( m_pDb, &pFirstNameNode)))
		{
			MAKE_FLM_ERROR_STRING( "getFirstChild failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pFirstNameNode->getNextSibling( m_pDb, &pLastNameNode)))
		{
			MAKE_FLM_ERROR_STRING( "getNextSibling failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pFirstNameNode->getUTF8( m_pDb, 
			(FLMBYTE *)szBuf, sizeof( szBuf), 0, sizeof( szBuf) - 1)))
		{
			MAKE_FLM_ERROR_STRING( "getUTF8 failed.", m_szDetails, rc);
			goto Exit;
		} 

		if ( f_strcmp( szBuf, ppszNames[uiLoop][0]) != 0)
		{
			rc = RC_SET( NE_XFLM_FAILURE);
			MAKE_FLM_ERROR_STRING( "Unexpected value.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pLastNameNode->getUTF8( m_pDb, 
			(FLMBYTE *)szBuf, sizeof( szBuf), 0, sizeof( szBuf) - 1)))
		{
			MAKE_FLM_ERROR_STRING( "getUTF8 failed.", m_szDetails, rc);
			goto Exit;
		} 

		if ( f_strcmp( szBuf, ppszNames[uiLoop][1]) != 0)
		{
			rc = RC_SET( NE_XFLM_FAILURE);
			MAKE_FLM_ERROR_STRING( "Unexpected value.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pQuery->getPosition( m_pDb, &uiPos)))
		{
			MAKE_FLM_ERROR_STRING( "getPosition failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( uiPos != uiLoop)
		{
			rc = RC_SET( NE_XFLM_FAILURE);
			MAKE_FLM_ERROR_STRING( "Unexpected position", m_szDetails, rc);
			goto Exit;
		}

	}

	endTest("PASS");

	f_sprintf( szTestName, pszTestNameFormat, uiCallCount,
		pszQuery, (unsigned)bFirstAscending, (unsigned)bLastAscending,
		"search key positioning");

	beginTest( szTestName, 
		"Ensure queries return proper results in proper order",
		"No Additional Info",
		"");
		
	if( RC_BAD( rc = m_pDbSystem->createIFDataVector( &pSearchKey)))
	{
		goto Exit;
	}

	// positioning tests 2

	for( uiLoop = 0; uiLoop < uiNumNames; uiLoop++)
	{

		if ( uiLoop == 0)
		{
			if ( RC_BAD( rc = pQuery->positionTo( 
				m_pDb, &pResultNode, 0, pSearchKey, XFLM_FIRST)))
			{
				MAKE_FLM_ERROR_STRING( "positionTo failed.", m_szDetails, rc);
				goto Exit;
			}
		}
		else
		{
			if ( RC_BAD( rc = pSearchKey->setUTF8( 0, 
				(FLMBYTE *)ppszNames[uiLoop][0])))
			{
				MAKE_FLM_ERROR_STRING( "setUTF8 failed.", m_szDetails, rc);
				goto Exit;
			}

			if ( RC_BAD( rc = pSearchKey->setUTF8( 1, 
				(FLMBYTE *)ppszNames[uiLoop][1])))
			{
				MAKE_FLM_ERROR_STRING( "setUTF8 failed.", m_szDetails, rc);
				goto Exit;
			}

			if ( RC_BAD( rc = pQuery->positionTo( 
				m_pDb, &pResultNode, 0, pSearchKey, XFLM_EXACT)))
			{
				MAKE_FLM_ERROR_STRING( "positionTo failed.", m_szDetails, rc);
				goto Exit;
			}
		}

		if ( RC_BAD( rc = pResultNode->getFirstChild( m_pDb, &pFirstNameNode)))
		{
			MAKE_FLM_ERROR_STRING( "getFirstChild failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pFirstNameNode->getNextSibling( m_pDb, &pLastNameNode)))
		{
			MAKE_FLM_ERROR_STRING( "getNextSibling failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pFirstNameNode->getUTF8( m_pDb,
			(FLMBYTE *)szBuf, sizeof( szBuf), 0, sizeof( szBuf) - 1)))
		{
			MAKE_FLM_ERROR_STRING( "getUTF8 failed.", m_szDetails, rc);
			goto Exit;
		} 

		if ( f_strcmp( szBuf, ppszNames[uiLoop][0]) != 0)
		{
			rc = RC_SET( NE_XFLM_FAILURE);
			MAKE_FLM_ERROR_STRING( "Unexpected value.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pLastNameNode->getUTF8( m_pDb, 
			(FLMBYTE *)szBuf, sizeof( szBuf), 0, sizeof( szBuf) - 1)))
		{
			MAKE_FLM_ERROR_STRING( "getUTF8 failed.", m_szDetails, rc);
			goto Exit;
		} 

		if ( f_strcmp( szBuf, ppszNames[uiLoop][1]) != 0)
		{
			rc = RC_SET( NE_XFLM_FAILURE);
			MAKE_FLM_ERROR_STRING( "Unexpected value.", m_szDetails, rc);
			goto Exit;
		}

		if ( RC_BAD( rc = pQuery->getPosition( m_pDb, &uiPos)))
		{
			MAKE_FLM_ERROR_STRING( "getPosition failed.", m_szDetails, rc);
			goto Exit;
		}

		if ( uiPos != uiLoop)
		{
			rc = RC_SET( NE_XFLM_FAILURE);
			MAKE_FLM_ERROR_STRING( "Unexpected position", m_szDetails, rc);
			goto Exit;
		}
	}

	endTest("PASS");

Exit:

	if( RC_BAD( rc))
	{
		endTest("FAIL");
	}

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

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

	if( pLastNameNode)
	{
		pLastNameNode->Release();
	}
	
	if( pSearchKey)
	{
		pSearchKey->Release();
	}

	return rc;
}
コード例 #14
0
ファイル: fqstack.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	Adds a field ID to the selection criteria of a given cursor.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmCursorAddField(
	HFCURSOR		hCursor,
	FLMUINT		uiFldId,
	FLMUINT		uiFlags)
{
	RCODE			rc = FERR_OK;
	CURSOR *		pCursor = (CURSOR *)hCursor;
	FQNODE *		pTmpQNode;
	FLMUINT		uiPath [2];

	if (!pCursor)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}

	if (RC_BAD( rc = pCursor->rc))
	{
		goto Exit;
	}

	// If a read operation has already been performed on this query, no
	// selection criteria may be added.
	
	if (pCursor->bOptimized)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}
	
	if (!( pCursor->QTInfo.uiExpecting & FLM_Q_OPERAND))
	{
		rc = RC_SET( FERR_CURSOR_SYNTAX);
		goto Exit;
	}

	if (uiFldId == FLM_RECID_FIELD)
	{
		uiFlags |= FLM_SINGLE_VALUED;
	}

	// Set up a field path with one element in it.

	uiPath [0] = uiFldId;
	uiPath [1] = 0;
	if (RC_OK( rc = flmCurMakeQNode( &pCursor->QueryPool, FLM_FLD_PATH,
							&uiPath [0], 0, pCursor->QTInfo.uiFlags, &pTmpQNode)))
	{
		pTmpQNode->pQAtom->uiFlags |= uiFlags;
		pCursor->QTInfo.pCurAtomNode = pTmpQNode;
		if (pCursor->QTInfo.pCurOpNode)
		{
			flmCurLinkLastChild( pCursor->QTInfo.pCurOpNode,
					pCursor->QTInfo.pCurAtomNode);
		}
		pCursor->QTInfo.uiExpecting &= ~FLM_Q_OPERAND;
		pCursor->QTInfo.uiExpecting |= FLM_Q_OPERATOR;
	}

Exit:
	if (pCursor)
	{
		pCursor->rc = rc;
	}
	return( rc);
}
コード例 #15
0
/****************************************************************************
Desc:	Finds the location of a wildcard in the internal text string, if any.
****************************************************************************/
FSTATIC RCODE flmUTF8FindWildcard(
	const FLMBYTE *	pucValue,
	FLMUINT *			puiCharPos,
	FLMUINT *			puiCompareRules)
{
	RCODE					rc = NE_SFLM_OK;
	const FLMBYTE *	pucSaveVal;
	const FLMBYTE *	pucStart = pucValue;
	FLMUNICODE			uzChar;
	FLMUINT				uiCompareRules = *puiCompareRules;

	flmAssert( pucValue);
	*puiCharPos = FLM_MAX_UINT;
	
	for( ;;)
	{
		pucSaveVal = pucValue;
		if (RC_BAD( rc = f_getCharFromUTF8Buf( &pucValue, NULL, &uzChar)))
		{
			goto Exit;
		}

		if (!uzChar)
		{
			break;
		}
		
		if ((uzChar = f_convertChar( uzChar, uiCompareRules)) == 0)
		{
			continue;
		}
		if (uzChar == ASCII_WILDCARD)
		{
			*puiCharPos = (FLMUINT)(pucSaveVal - pucStart);
			goto Exit;
		}
		if (uzChar != ASCII_SPACE)
		{
			
			// Once we hit a non-space character - except for the wildcard,
			// we can remove the ignore leading space rule.
			
			uiCompareRules &= (~(FLM_COMP_IGNORE_LEADING_SPACE));
			if (uzChar == ASCII_BACKSLASH)
			{
	
				// Skip the escaped character
	
				if (RC_BAD( rc = f_getCharFromUTF8Buf( &pucValue, NULL, &uzChar)))
				{
					goto Exit;
				}
	
				if (!uzChar)
				{
					rc = RC_SET( NE_SFLM_Q_BAD_SEARCH_STRING);
					goto Exit;
				}
			}
		}
	}

Exit:

	*puiCompareRules = uiCompareRules;

	return( rc);
}
コード例 #16
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	Forces a checkpoint on the database.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmDbCheckpoint(
	HFDB			hDb,
	FLMUINT		uiTimeout)
{
	RCODE			rc = FERR_OK;
	FDB *			pDb = (FDB *)hDb;
	FLMBOOL		bStartedTrans;

	bStartedTrans = FALSE;

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

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

		if( !pCSContext->bConnectionGood)
		{
			rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
			goto Transmission_Error;
		}

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

		if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiTimeout)))
		{
			goto Transmission_Error;
		}

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

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

		if( RC_BAD( rc = Wire.getRCode()))
		{
			goto Exit;
		}

		goto Exit;

Transmission_Error:

		pCSContext->bConnectionGood = FALSE;
		goto Exit;
	}

	// Start an update transaction.  Must not already be one going.

	if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
									  0, uiTimeout | FLM_AUTO_TRANS, &bStartedTrans)))
	{
		goto Exit;
	}

	// Commit the transaction, forcing it to be checkpointed.

	bStartedTrans = FALSE;
	pDb->bHadUpdOper = FALSE;
	if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE)))
	{
		goto Exit;
	}
	
Exit:

	if (bStartedTrans)
	{
		(void)flmAbortDbTrans( pDb);
	}

	flmExit( FLM_DB_CHECKPOINT, pDb, rc);
	return( rc);
}
コード例 #17
0
/****************************************************************************
Desc:	Method to get a new F_BtResultSet object.  This method will create a
		new collection for the result set to use before handing it off.
****************************************************************************/
RCODE F_DbCheck::getBtResultSet(
	F_BtResultSet **	ppBtRSet
	)
{
	RCODE					rc = NE_XFLM_OK;
	FLMUINT				uiCollection;
	F_BtResultSet *	pBtRSet = NULL;
	F_Database *		pDatabase = NULL;

	// If there is already a BtResultSet, let's get rid of it.
	
	if (*ppBtRSet)
	{
		(*ppBtRSet)->Release();
		*ppBtRSet = NULL;
	}

	// Create the new BtResultSet object first.
	
	if ((pBtRSet = f_new F_BtResultSet( m_pResultSetDb, m_pBtPool)) == NULL)
	{
		rc = RC_SET( NE_XFLM_MEM);
		goto Exit;
	}

	pDatabase = m_pResultSetDb->m_pDatabase;

	for (;;)
	{

		// Now create a new collection.  Randomly select a collection number to use.
		
		uiCollection = m_pRandGen->getUINT32( 100, XFLM_MAX_COLLECTION_NUM);
	
		// Check to see if it already exists.
		
		if (RC_OK( rc = pDatabase->lFileCreate( m_pResultSetDb,
			&pBtRSet->m_Collection.lfInfo, &pBtRSet->m_Collection, uiCollection,
			XFLM_LF_COLLECTION, FALSE, TRUE)))
		{
			break;
		}
		
		if (rc != NE_XFLM_EXISTS)
		{
			goto Exit;
		}
		rc = NE_XFLM_OK;
	}

	*ppBtRSet = pBtRSet;
	pBtRSet = NULL;

Exit:

	if (pBtRSet)
	{
		pBtRSet->Release();
	}
	
	return rc;
}
コード例 #18
0
ファイル: ftrans.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	This routine starts a transaction for the specified database.  The
		transaction may be part of an overall larger transaction.
****************************************************************************/
RCODE flmBeginDbTrans(
	FDB *			pDb,
	FLMUINT		uiTransType,
	FLMUINT		uiMaxLockWait,
	FLMUINT		uiFlags,
	FLMBYTE *	pucLogHdr)
{
	RCODE			rc = FERR_OK;
	FFILE *		pFile = pDb->pFile;
	FLMBOOL		bMutexLocked = FALSE;
	FLMBYTE *	pucLastCommittedLogHdr;
	DB_STATS *	pDbStats = pDb->pDbStats;

	if( RC_BAD( rc = flmCheckDatabaseState( pDb)))
	{
		goto Exit;
	}

	// Initialize a few things - as few as is necessary to avoid
	// unnecessary overhead.

	pDb->eAbortFuncId = FLM_UNKNOWN_FUNC;
	pDb->AbortRc = FERR_OK;
	pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0];
	pDb->KrefCntrl.bKrefSetup = FALSE;
	pDb->uiTransType = uiTransType;
	pDb->uiThreadId = (FLMUINT)f_threadId();
	pDb->uiTransCount++;

	// Link the FDB to the file's most current FDICT structure,
	// if there is one.
	//
	// Also, if it is a read transaction, link the FDB
	// into the list of read transactions off of
	// the FFILE structure.

	f_mutexLock( gv_FlmSysData.hShareMutex);
	bMutexLocked = TRUE;
	if (pFile->pDictList)
	{

		// Link the FDB to the FDICT.

		flmLinkFdbToDict( pDb, pFile->pDictList);
	}

	// If it is a read transaction, link into the list of
	// read transactions off of the FFILE structure.  Until we
	// get the log header transaction ID below, we set uiCurrTransID
	// to zero and link this transaction in at the beginning of the
	// list.

	if (uiTransType == FLM_READ_TRANS)
	{
		flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr);

		// Link in at the end of the transaction list.

		pDb->pNextReadTrans = NULL;
		if ((pDb->pPrevReadTrans = pFile->pLastReadTrans) != NULL)
		{

			// Make sure transaction IDs are always in ascending order.  They
			// should be at this point.

			flmAssert( pFile->pLastReadTrans->LogHdr.uiCurrTransID <=
							pDb->LogHdr.uiCurrTransID);
			pFile->pLastReadTrans->pNextReadTrans = pDb;
		}
		else
		{
			pFile->pFirstReadTrans = pDb;
		}
		pFile->pLastReadTrans = pDb;
		pDb->uiInactiveTime = 0;

		if( uiFlags & FLM_DONT_KILL_TRANS)
		{
			pDb->uiFlags |= FDB_DONT_KILL_TRANS;
		}
		else
		{
			pDb->uiFlags &= ~FDB_DONT_KILL_TRANS;
		}
		
		if (pucLogHdr)
		{
			f_memcpy( pucLogHdr, &pDb->pFile->ucLastCommittedLogHdr[0],
						LOG_HEADER_SIZE);
		}
	}

	f_mutexUnlock( gv_FlmSysData.hShareMutex);
	bMutexLocked = FALSE;

	if( uiFlags & FLM_DONT_POISON_CACHE)
	{
		pDb->uiFlags |= FDB_DONT_POISON_CACHE;
	}
	else
	{
		pDb->uiFlags &= ~FDB_DONT_POISON_CACHE;
	}

	// Put an exclusive lock on the database if we are not in a read
	// transaction.  Read transactions require no lock.

	if (uiTransType != FLM_READ_TRANS)
	{
		flmAssert( pDb->pIxStats == NULL);

		// Set the bHadUpdOper to TRUE for all transactions to begin with.
		// Many calls to flmBeginDbTrans are internal, and we WANT the
		// normal behavior at the end of the transaction when it is
		// committed or aborted.  The only time this flag will be set
		// to FALSE is when the application starts the transaction as
		// opposed to an internal starting of the transaction.

		pDb->bHadUpdOper = TRUE;

		// Initialize the count of blocks changed to be 0

		pDb->uiBlkChangeCnt = 0;

		if (RC_BAD( rc = dbLock( pDb, uiMaxLockWait)))
		{
			goto Exit;
		}

		// If there was a problem with the RFL volume, we must wait
		// for a checkpoint to be completed before continuing.
		// The checkpoint thread looks at this same flag and forces
		// a checkpoint.  If it completes one successfully, it will
		// reset this flag.
		//
		// Also, if the last forced checkpoint had a problem
		// (pFile->CheckpointRc != FERR_OK), we don't want to
		// start up a new update transaction until it is resolved.

		if (!pFile->pRfl->seeIfRflVolumeOk() ||
			 RC_BAD( pFile->CheckpointRc))
		{
			rc = RC_SET( FERR_MUST_WAIT_CHECKPOINT);
			goto Exit;
		}

		// Set the first log block address to zero.

		pFile->uiFirstLogBlkAddress = 0;

		// Header must be read before opening roll forward log file to make
		// sure we have the most current log file and log options.

		f_memcpy( pFile->ucUncommittedLogHdr, pucLastCommittedLogHdr,
			LOG_HEADER_SIZE);
		flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr);

		// Need to increment the current checkpoint for update transactions
		// so that it will be correct when we go to mark cache blocks.

		if (pDb->uiFlags & FDB_REPLAYING_RFL)
		{
			// During recovery we need to set the transaction ID to the
			// transaction ID that was logged.

			pDb->LogHdr.uiCurrTransID = pFile->pRfl->getCurrTransID();
		}
		else
		{
			pDb->LogHdr.uiCurrTransID++;
		}
		f_mutexLock( gv_FlmSysData.hShareMutex);

		// Link FDB to the most current local dictionary, if there
		// is one.

		if (pFile->pDictList != pDb->pDict && pFile->pDictList)
		{
			flmLinkFdbToDict( pDb, pFile->pDictList);
		}
		pFile->uiUpdateTransID = pDb->LogHdr.uiCurrTransID;
		f_mutexUnlock( gv_FlmSysData.hShareMutex);

		// Set the transaction EOF to the current file EOF

		pDb->uiTransEOF = pDb->LogHdr.uiLogicalEOF;

		// Put the transaction ID into the uncommitted log header.

		UD2FBA( (FLMUINT32)pDb->LogHdr.uiCurrTransID,
					&pFile->ucUncommittedLogHdr [LOG_CURR_TRANS_ID]);

		if (pucLogHdr)
		{
			f_memcpy( pucLogHdr, &pDb->pFile->ucUncommittedLogHdr [0],
							LOG_HEADER_SIZE);
		}
	}

	if (pDbStats)
	{
		f_timeGetTimeStamp( &pDb->TransStartTime);
	}

	// If we do not have a dictionary, read it in from disk.
	// NOTE: This should only happen when we are first opening
	// the database.

	if (!pDb->pDict)
	{
		flmAssert( pDb->pFile->uiFlags & DBF_BEING_OPENED);
	
		if (RC_BAD( rc = fdictRebuild( pDb)))
		{
			if (pDb->pDict)
			{
				flmFreeDict( pDb->pDict);
				pDb->pDict = NULL;
			}
			
			goto Exit;
		}
	
		f_mutexLock( gv_FlmSysData.hShareMutex);
	
		// At this point, we will not yet have opened the database for
		// general use, so there is no way that any other thread can have
		// created a dictionary yet.
	
		flmAssert( pDb->pFile->pDictList == NULL);
	
		// Link the new local dictionary to its file structure.
	
		flmLinkDictToFile( pDb->pFile, pDb->pDict);
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
	}

Exit:

	if( bMutexLocked)
	{
		f_mutexUnlock( gv_FlmSysData.hShareMutex);
	}

	if (uiTransType != FLM_READ_TRANS)
	{
		if (RC_OK( rc))
		{
			rc = pFile->pRfl->logBeginTransaction( pDb);
		}
#ifdef FLM_DBG_LOG
		flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID,
				0, 0, rc, "TBeg");
#endif
	}

	if( uiTransType == FLM_UPDATE_TRANS &&
		 gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmTransEventCallback( F_EVENT_BEGIN_TRANS, (HFDB)pDb, rc,
					(FLMUINT)(RC_OK( rc)
								 ? pDb->LogHdr.uiCurrTransID
								 : (FLMUINT)0));
	}

	if (RC_BAD( rc))
	{
		// If there was an error, unlink the database from the transaction
		// structure as well as from the FDICT structure.

		flmUnlinkDbFromTrans( pDb, FALSE);

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

	return( rc);
}
コード例 #19
0
/********************************************************************
Desc: This routine follows all of the blocks in a chain, verifying
		that they are properly linked.  It also verifies each block's
		header.
*********************************************************************/
RCODE F_DbCheck::verifyBlkChain(
	BLOCK_INFO *	pBlkInfo,
	FLMUINT			uiLocale,
	FLMUINT			uiFirstBlkAddr,
	FLMUINT			uiBlkType,
	FLMBOOL *		pbStartOverRV
	)
{
	RCODE					rc = NE_XFLM_OK;
	FLMINT32				i32VerifyCode = 0;
	F_CachedBlock *	pSCache = NULL;
	F_BLK_HDR *			pBlkHdr = NULL;
	FLMUINT				uiPrevBlkAddress;
	FLMUINT				uiBlkCount = 0;
	STATE_INFO			StateInfo;
	FLMBOOL				bStateInitialized = FALSE;
	FLMUINT64			ui64SaveBytesExamined;
	FLMUINT				uiBlockSize = m_pDb->m_pDatabase->getBlockSize();
	FLMUINT				uiMaxBlocks = (FLMUINT)(FSGetSizeInBytes(
										m_pDb->m_pDatabase->getMaxFileSize(),
											m_pDb->m_uiLogicalEOF) /
											(FLMUINT64)uiBlockSize);

	uiPrevBlkAddress = 0;

	/* There must be at least ONE block if it is the LFH chain. */

	if ((uiBlkType == BT_LFH_BLK) && (uiFirstBlkAddr == 0))
	{
		i32VerifyCode = FLM_BAD_LFH_LIST_PTR;
		(void)chkReportError( i32VerifyCode,
									 (FLMUINT32)uiLocale,
									 0,
									 0,
									 0xFF,
									 0,
									 0,
									 0,
									 0);
		goto Exit;
	}

	/* Read through all of the blocks, verifying them as we go. */

Restart_Chain:
	uiBlkCount = 0;
	flmInitReadState( &StateInfo,
							&bStateInitialized,
							(FLMUINT)m_pDb->m_pDatabase->
											m_lastCommittedDbHdr.ui32DbVersion,
							m_pDb,
							NULL,
							(FLMUINT)((uiBlkType == BT_FREE)
											? (FLMUINT)0xFF
											: (FLMUINT)0),
							uiBlkType,
							NULL);
	
	ui64SaveBytesExamined = m_Progress.ui64BytesExamined;
	StateInfo.ui32BlkAddress = (FLMUINT32)uiFirstBlkAddr;

	while ((StateInfo.ui32BlkAddress != 0) && (uiBlkCount < uiMaxBlocks))
	{
		StateInfo.pBlkHdr = NULL;
		if( RC_BAD( rc = blkRead( StateInfo.ui32BlkAddress, &pBlkHdr,
			&pSCache, &i32VerifyCode)))
		{
			if (rc == NE_XFLM_OLD_VIEW)
			{
				FLMUINT	uiSaveDictSeq = m_pDb->m_pDict->getDictSeq();

				if (RC_BAD( rc = getDictInfo()))
					goto Exit;

				// If the dictionary ID changed, start over.

				if (m_pDb->m_pDict->getDictSeq() != uiSaveDictSeq)
				{
					*pbStartOverRV = TRUE;
					goto Exit;
				}

				m_Progress.ui64BytesExamined = ui64SaveBytesExamined;
				goto Restart_Chain;
			}
			pBlkInfo->i32ErrCode = i32VerifyCode;
			pBlkInfo->uiNumErrors++;
			rc = chkReportError( i32VerifyCode,
										(FLMUINT32)uiLocale,
										0,
										0,
										0xFF,
										StateInfo.ui32BlkAddress,
										0,
										0,
										0);
		}
		StateInfo.pBlkHdr = pBlkHdr;
		uiBlkCount++;
		m_Progress.ui64BytesExamined += (FLMUINT64)uiBlockSize;
		if (RC_BAD( rc = chkCallProgFunc()))
		{
			goto Exit;
		}

		f_yieldCPU();

		if ((i32VerifyCode = flmVerifyBlockHeader( &StateInfo,
															  pBlkInfo,
															  uiBlockSize,
															  0xFFFFFFFF,
															  uiPrevBlkAddress,
															  TRUE)) != 0)
		{
			pBlkInfo->i32ErrCode = i32VerifyCode;
			pBlkInfo->uiNumErrors++;
			chkReportError( i32VerifyCode,
								 (FLMUINT32)uiLocale,
								 0,
								 0,
								 0xFF,
								 StateInfo.ui32BlkAddress,
								 0,
								 0,
								 0);
			goto Exit;
		}
		uiPrevBlkAddress = StateInfo.ui32BlkAddress;
		StateInfo.ui32BlkAddress = pBlkHdr->ui32NextBlkInChain;
	}
	if (StateInfo.ui32BlkAddress != 0 && RC_OK( m_LastStatusRc))
	{
		switch (uiBlkType)
		{
			case BT_LFH_BLK:
				i32VerifyCode = FLM_BAD_LFH_LIST_END;
				break;
			case BT_FREE:
				i32VerifyCode = FLM_BAD_AVAIL_LIST_END;
				break;
		}
		pBlkInfo->i32ErrCode = i32VerifyCode;
		pBlkInfo->uiNumErrors++;
		chkReportError( i32VerifyCode,
							 (FLMUINT32)uiLocale,
							 0,
							 0,
							 0xFF,
							 (FLMUINT32)uiPrevBlkAddress,
							 0,
							 0,
							 0);
		goto Exit;
	}

Exit:

	if( pSCache)
	{
		ScaReleaseCache( pSCache, FALSE);
	}
	else if( pBlkHdr)
	{
		f_free( &pBlkHdr);
	}

	if (RC_OK(rc) && (i32VerifyCode != 0))
	{
		rc = RC_SET( NE_XFLM_DATA_ERROR);
	}

	return( rc);
}
コード例 #20
0
ファイル: ftkmfh.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc: Opens an existing 64-bit file
****************************************************************************/
RCODE F_MultiFileHdl::openFile(
	const char *	pszPath)
{
	RCODE					rc = NE_FLM_OK;
	IF_FileSystem *	pFileSystem = f_getFileSysPtr();
	IF_DirHdl *			pDir = NULL;
	FLMUINT				uiTmp;
	FLMUINT				uiHighFileNum = 0;
	FLMUINT64			ui64HighOffset = 0;

	if( m_bOpen)
	{
		rc = RC_SET_AND_ASSERT( NE_FLM_FAILURE);
		goto Exit;
	}

	if( RC_BAD( pFileSystem->doesFileExist( pszPath)) ||
		!pFileSystem->isDir( pszPath))
	{
		rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND);
		goto Exit;
	}

	f_strcpy( m_szPath, pszPath);

	// Create the lock file

	if( RC_BAD( rc = createLockFile( m_szPath)))
	{
		goto Exit;
	}

	// Need to determine the current EOF

	if( RC_BAD( rc = pFileSystem->openDir( m_szPath, (char *)"*.64", &pDir)))
	{
		goto Exit;
	}

	// Find all data files to determine the EOF

	for( rc = pDir->next(); !RC_BAD( rc); rc = pDir->next())
	{
		if( RC_OK( getFileNum( pDir->currentItemName(), &uiTmp)))
		{
			if( uiTmp >= uiHighFileNum)
			{
				uiHighFileNum = uiTmp;
				ui64HighOffset = pDir->currentItemSize();
			}
		}
	}
	rc = NE_FLM_OK;

	m_ui64EOF = (((FLMUINT64)uiHighFileNum) * m_uiMaxFileSize) + ui64HighOffset;
	m_bOpen = TRUE;

Exit:

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

	// Release the lock file

	if( RC_BAD( rc))
	{
		releaseLockFile( m_szPath, FALSE);
	}

	return( rc);
}
コード例 #21
0
ファイル: flmimon.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc:	This is the function that the HTTP server calls when it wants to
			display one of our pages
****************************************************************************/
int flmHttpCallback(
	HRequest *			pHRequest,
	void *				//pvUserData
	)
{
	RCODE							rc = FERR_OK;
	F_WebPage *					pPage = NULL;
	char *						pszPath = NULL;
	char *						pszQuery = NULL;
	char *						pszTemp = NULL;
	const char *				pszConstTemp = NULL;
#define MAX_PARAMS 10
	const char *				pszParams[ MAX_PARAMS];
	FLMUINT						uiNumParams;

	// If we get a NULL for the pHRequest object, then we are shutting down...

	if (pHRequest == NULL)
	{
		// Remove the globals that enable the secure pages...
		gv_FlmSysData.HttpConfigParms.fnSetGblValue( 
				FLM_SECURE_PASSWORD, "", 0);
		gv_FlmSysData.HttpConfigParms.fnSetGblValue(
				FLM_SECURE_EXPIRATION, "", 0);

		// Delete the web page factory object
		if (gv_pWPFact)
		{
			gv_pWPFact->Release( NULL);
		}
		gv_pWPFact = NULL;
		goto Exit;
	}

	// Increment the use count (helps ensure that the function pointers
	// that display() references don't go away while display() still needs
	// them.

	f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex);
	gv_FlmSysData.HttpConfigParms.uiUseCount++;
	f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);

	// Must not access any HRequest function pointers prior to incrementing the
	// use count.

	if( !gv_FlmSysData.HttpConfigParms.fnReqPath)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_FAILURE);
		goto Exit;
	}

	// If the web page factory does not exist yet, then we need to create it.
	if (!gv_pWPFact)
	{
		f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex);
		// In the time it took us to get the lock, some other thread might
		// have come along and created the factory already...
		if (!gv_pWPFact)
		{
			if ((gv_pWPFact = f_new F_WebPageFactory) == NULL)
			{
				rc = RC_SET( FERR_MEM);
				f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);
				goto Exit;
			}
		}
		f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);
	}
	
	pszConstTemp = gv_FlmSysData.HttpConfigParms.fnReqPath( pHRequest);
	flmAssert( pszConstTemp);

	if( RC_BAD( rc = f_alloc( 
		f_strlen( pszConstTemp) + 1, &pszPath)))
	{
		goto Exit;
	}

	f_strcpy( pszPath, pszConstTemp);
	
	pszConstTemp = gv_FlmSysData.HttpConfigParms.fnReqQuery( pHRequest);
	if( pszConstTemp)
	{
		if( RC_BAD( rc = f_alloc( f_strlen( pszConstTemp) + 1, &pszQuery)))
		{
			goto Exit;
		}

		f_strcpy( pszQuery, pszConstTemp);
		pszConstTemp = pszQuery;
	}
	else  // This URL had no query string...
	{
		// If pszQuery is NULL, it causes problems further down, so we'll
		// make it a pointer to a null string...

		if( RC_BAD( rc = f_alloc( 1, &pszQuery)))
		{
			goto Exit;
		}
		pszQuery[0] = '\0';				
	}

	// Strip off pszURLString (and the next '/', if there is one) from the request and store 
	// what's left as pszParams[0].
	// (ie: /coredb/FlmSysData --> FlmSysData)

	// Note: The reason we're checking for the URL string first is because if
	// we're using our own http stack, then this callback is called for every
	// http request and we don't want to crash if we've got a short URI.
	// When we're running under DS, we're guarenteed that the URLString will
	// be part of the URI.

	if( f_strlen( pszPath) >= gv_FlmSysData.HttpConfigParms.uiURLStringLen)
	{
		pszConstTemp = pszPath + gv_FlmSysData.HttpConfigParms.uiURLStringLen;
		if( *pszConstTemp == '/')
		{
			pszConstTemp++;
		}
	}
	else
	{
		pszConstTemp = pszPath;
	}

	pszParams[0] = pszConstTemp;
	uiNumParams = 1;


	// Parse parameters in the query string 
	// Note that it's technically incorrect to have more than one ? in a
	// URL, but we didn't know that when we first started creating some of 
	// these pages and as a result, some queries are in the form of:
	// ?name1=value1?name2=value2?name3=value3...  (which is improper) and
	// some have the form:
	// ?name1=value1&name2=value2&name3=value3... (which is correct).
	
	pszTemp = pszQuery;
	
	while( *pszTemp != 0)
	{
		flmAssert( uiNumParams < MAX_PARAMS);
		pszParams[ uiNumParams] = pszTemp;
		uiNumParams++;
		
		pszTemp = tokenizer( pszTemp, '?', '&');
		
		if (*pszTemp)
		{
			*pszTemp = '\0';
			pszTemp++;
		}
	}

	// Tell the factory to create the page
	
	if (RC_BAD( rc = gv_pWPFact->create( pszParams[0], &pPage, pHRequest)))
	{
		goto Exit;
	}
	
	
	pPage->setMembers( pHRequest);

	// display the page
	if( RC_BAD( rc = pPage->display (uiNumParams, &pszParams[0])))
	{
		goto Exit;
	}

Exit:

	// Decrement the use count

	if( pHRequest)
	{
		f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex);
		if( gv_FlmSysData.HttpConfigParms.uiUseCount > 0)
		{
			gv_FlmSysData.HttpConfigParms.uiUseCount--;
		}
		else
		{
			flmAssert( 0);
		}
		f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex);
	}
	
	if (pPage)
	{
		gv_pWPFact->Release( &pPage);
	}

	if (pszPath)
	{
		f_free( &pszPath);
	}

	if (pszQuery)
	{
		f_free( &pszQuery);
	}

	return (int)rc;
}
コード例 #22
0
ファイル: ftkmfh.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc: Reads data from the file
****************************************************************************/
RCODE F_MultiFileHdl::read(
	FLMUINT64	ui64Offset,				// Offset to begin reading
	FLMUINT		uiLength,				// Number of bytes to read
	void *		pvBuffer,				// Buffer
	FLMUINT *	puiBytesRead)			// [out] Number of bytes read
{
	RCODE				rc = NE_FLM_OK;
	FLMUINT			uiFileNum = getFileNum( ui64Offset);
	FLMUINT			uiFileOffset = getFileOffset( ui64Offset);
	FLMUINT			uiTmp;
	FLMUINT			uiTotalBytesRead = 0;
	FLMUINT			uiBytesToRead;
	FLMUINT			uiMaxReadLen;
	IF_FileHdl *	pFileHdl;

	// Handle the case of a 0-byte read

	if( !uiLength)
	{
		if( ui64Offset >= m_ui64EOF)
		{
			rc = RC_SET( NE_FLM_IO_END_OF_FILE);
		}
		goto Exit;
	}

	// Read the data file(s), moving to new files as needed.

	for( ;;)
	{
		if( ui64Offset >= m_ui64EOF)
		{
			rc = RC_SET( NE_FLM_IO_END_OF_FILE);
			goto Exit;
		}

		uiMaxReadLen = m_uiMaxFileSize - uiFileOffset;
		f_assert( uiMaxReadLen != 0);
		uiTmp = (uiLength >= uiMaxReadLen ? uiMaxReadLen : uiLength);
		uiBytesToRead = (((FLMUINT64)uiTmp > (FLMUINT64)(m_ui64EOF - ui64Offset))
								? (FLMUINT)(m_ui64EOF - ui64Offset)
								: uiTmp);

		if( RC_BAD( rc = getFileHdl( uiFileNum, FALSE, &pFileHdl)))
		{
			if( rc == NE_FLM_IO_PATH_NOT_FOUND)
			{
				// Handle the case of a sparse file by filling the unread
				// portion of the buffer with zeros.

				f_memset( pvBuffer, 0, uiBytesToRead);
				uiTmp = uiBytesToRead;
				rc = NE_FLM_OK;
			}
			else
			{
				goto Exit;
			}
		}
		else
		{
			if( RC_BAD( rc = pFileHdl->read( uiFileOffset, uiBytesToRead,
				pvBuffer, &uiTmp)))
			{
				if( rc == NE_FLM_IO_END_OF_FILE)
				{
					// Handle the case of a sparse file by filling the unread
					// portion of the buffer with zeros.

					f_memset( &(((FLMBYTE *)(pvBuffer))[ uiTmp]),
						0, (FLMUINT)(uiBytesToRead - uiTmp));
					uiTmp = uiBytesToRead;
					rc = NE_FLM_OK;
				}
				else
				{
					goto Exit;
				}
			}
		}

		uiTotalBytesRead += uiTmp;
		uiLength -= uiTmp;
		if( !uiLength)
		{
			break;
		}

		// Set up for next read

		pvBuffer = ((FLMBYTE *)pvBuffer) + uiTmp;
		ui64Offset += uiTmp;
		uiFileNum = getFileNum( ui64Offset);
		uiFileOffset = getFileOffset( ui64Offset);
	}

Exit:

	*puiBytesRead = uiTotalBytesRead;
	return( rc);
}
コード例 #23
0
/****************************************************************************
Desc:	Returns specific information about the most recent error that
		occured within FLAIM.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmGetDiagInfo(
	HFDB				hDb,
	eDiagInfoType	eDiagCode,
	void *			pvDiagInfo)
{
	RCODE		rc = FERR_OK;
	FDB *		pDb;

	if ((pDb = (FDB *)hDb) == NULL)
	{
		rc = RC_SET( FERR_NOT_FOUND);
		goto Exit;
	}
	fdbUseCheck( pDb);

	/* Now, copy over the data into the users variable */
	switch( eDiagCode)
	{
		case FLM_GET_DIAG_INDEX_NUM :
			if (!(pDb->Diag.uiInfoFlags & FLM_DIAG_INDEX_NUM))
			{
				rc = RC_SET( FERR_NOT_FOUND);
				goto Exit;
			}
			else
			{
				*((FLMUINT *)pvDiagInfo) = pDb->Diag.uiIndexNum;
			}
			break;

		case FLM_GET_DIAG_DRN :
			if (!(pDb->Diag.uiInfoFlags & FLM_DIAG_DRN))
			{
				rc = RC_SET( FERR_NOT_FOUND);
				goto Exit;
			}
			else
			{
				*((FLMUINT *)pvDiagInfo) = pDb->Diag.uiDrn;
			}
			break;

		case FLM_GET_DIAG_FIELD_NUM :
			if (!(pDb->Diag.uiInfoFlags & FLM_DIAG_FIELD_NUM))
			{
				rc = RC_SET( FERR_NOT_FOUND);
				goto Exit;
			}
			else
			{
				*((FLMUINT *)pvDiagInfo) = pDb->Diag.uiFieldNum;
			}
			break;

		case FLM_GET_DIAG_FIELD_TYPE :
			if (!(pDb->Diag.uiInfoFlags & FLM_DIAG_FIELD_TYPE))
			{
				rc = RC_SET( FERR_NOT_FOUND);
				goto Exit;
			}
			else
			{
				*((FLMUINT *)pvDiagInfo) = pDb->Diag.uiFieldType;
			}
			break;

		case FLM_GET_DIAG_ENC_ID :
			if (!(pDb->Diag.uiInfoFlags & FLM_DIAG_ENC_ID))
			{
				rc = RC_SET( FERR_NOT_FOUND);
				goto Exit;
			}
			else
			{
				*((FLMUINT *)pvDiagInfo) = pDb->Diag.uiEncId;
			}
			break;
		default:
			flmAssert( 0);
			rc = RC_SET( FERR_NOT_FOUND);
			goto Exit;

	}

Exit:
	if( pDb)
	{
		fdbUnuse( pDb);
	}
	return( rc);
}
コード例 #24
0
ファイル: ftkmfh.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc: This routine obtains exclusive access to a 64-bit file by creating
		a .lck file.  The object holds the .lck file open as long as the
		64-bit file is open.
****************************************************************************/
RCODE F_MultiFileHdl::createLockFile(
	const char *		pszBasePath)
{
	RCODE					rc = NE_FLM_OK;
	char					szLockPath [F_PATH_MAX_SIZE];
	F_FileHdl *			pLockFileHdl = NULL;
	FLMUINT				uiIoFlags = FLM_IO_RDWR | FLM_IO_EXCL | FLM_IO_SH_DENYRW;
	IF_FileSystem *	pFileSystem = f_getFileSysPtr();

	f_strcpy( szLockPath, pszBasePath);
	pFileSystem->pathAppend( szLockPath, "64.LCK");

	// Attempt to create the lock file.  If it fails, the lock file
	// may have been left because of a crash.  Hence, we first try
	// to delete the file.  If that succeeds, we then attempt to
	// create the file again.  If it, or the 2nd create fail, we simply
	// return an access denied error.
	
	if( RC_BAD( rc = f_allocFileHdl( &pLockFileHdl)))
	{
		goto Exit;
	}

#ifndef FLM_UNIX
	// On Unix, we do not want to delete the file because it
	// will succeed even if someone else has the file open.
	
	uiIoFlags |= FLM_IO_DELETE_ON_RELEASE;
#endif

	if( RC_BAD( pLockFileHdl->createFile( szLockPath, uiIoFlags)))
	{
#ifndef FLM_UNIX
		if (RC_BAD( pFileSystem->deleteFile( szLockPath)))
		{
			rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
			goto Exit;
		}
		else if (RC_BAD( pLockFileHdl->createFile( szLockPath, uiIoFlags)))
		{
			rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
			goto Exit;
		}
#else

		if( RC_BAD( pLockFileHdl->openFile( szLockPath, uiIoFlags)))
		{
			rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
			goto Exit;
		}
#endif
	}

#ifdef FLM_UNIX
	if( RC_BAD( pLockFileHdl->lock()))
	{
		rc = RC_SET( NE_FLM_IO_ACCESS_DENIED);
		goto Exit;
	}
#endif

	m_pLockFileHdl = pLockFileHdl;
	pLockFileHdl = NULL;

Exit:

	if (pLockFileHdl)
	{
		(void)pLockFileHdl->closeFile();
		pLockFileHdl->Release();
		pLockFileHdl = NULL;
	}
	return( rc);
}
コード例 #25
0
/****************************************************************************
Desc:	Insert the entry into the btree - should be positioned
****************************************************************************/
RCODE F_BtreeRoot::insert(
	void *			pvEntry)
{
	RCODE				rc = NE_FLM_OK;
	FLMUINT			uiCurLevel;
	FLMBYTE			ucEntryBuf[FBTREE_MAX_LEVELS][DYNSSET_MAX_FIXED_ENTRY_SIZE];
	FLMUINT			uiNewBlkAddr;

	if (RC_OK( rc = m_BTStack[0]->insert( pvEntry)))
	{
		goto Exit;
	}

	// Failed to input at the left level.  Do block split(s).
	// This is an iterative and NOT a recursive split algorithm.
	// The debugging, and cases to test should be lots easier this way.
	
	f_memcpy( ucEntryBuf[0], pvEntry, m_uiEntrySize);
	uiCurLevel = 0;
	uiNewBlkAddr = FBTREE_END;
	for(;;)
	{

		// Split while adding the element.

		if (RC_BAD( rc = (m_BTStack[uiCurLevel])->split( 
											this,
											ucEntryBuf[ uiCurLevel],
											uiNewBlkAddr,	
											ucEntryBuf[ uiCurLevel+1],
											&uiNewBlkAddr)))
		{
			goto Exit;
		}

		uiCurLevel++;
		flmAssert( uiCurLevel < m_uiLevels);

		if (RC_OK( rc = m_BTStack[uiCurLevel]->insertEntry( 
									ucEntryBuf[uiCurLevel], uiNewBlkAddr)))
		{
			goto Exit;
		}

		// Only returns NE_FLM_OK or FAILURE.

		// Root split?

		if (uiCurLevel + 1 == m_uiLevels)
		{
			flmAssert( m_uiLevels + 1 <= FBTREE_MAX_LEVELS);
			if (m_uiLevels + 1 > FBTREE_MAX_LEVELS)
			{
				rc = RC_SET( NE_FLM_BTREE_FULL);
				goto Exit;
			}

			// Need to split the root block.
			 rc = ((F_BtreeRoot *)m_BTStack[uiCurLevel])->split( 
						ucEntryBuf[uiCurLevel], uiNewBlkAddr );
			 break;
		}
	}

Exit:

	if (RC_OK(rc))
	{
		m_uiTotalEntries++;
	}
	return( rc);
}
コード例 #26
0
/****************************************************************************
Desc:	Parse a single line from the ini file into its name, value and comment
	   parts.
****************************************************************************/
RCODE F_IniFile::parseBuffer(
	char *		pszBuf,
	FLMUINT		uiNumBytes)
{
	RCODE			rc = NE_FLM_OK;
	FLMUINT		uiCurrentChar = 0;
	char *		pszNameStart = NULL;
	char *		pszNameEnd = NULL;
	char *		pszValStart = NULL;
	char *		pszValEnd = NULL;
	char *		pszCommentStart = NULL;
	INI_LINE *	pLine = NULL;
	FLMUINT		uiStrLen = 0;

	f_assert( pszBuf);
	f_assert( uiNumBytes);

	// Start looking for the parameter name...
	
	while (uiCurrentChar < uiNumBytes)
	{
		if( !isWhiteSpace( pszBuf[uiCurrentChar]))
		{
			if (pszBuf[uiCurrentChar] == '#') 
			{
				goto Comment;
			}
			else
			{
				pszNameStart = &pszBuf[uiCurrentChar];
				break;
			}
		}
		uiCurrentChar++;
	}

	// We've found a param name, now mark the end of it
	// We determine the end by looking for whitespace or '='
	// or '#'
	
	while (uiCurrentChar < uiNumBytes)
	{
		if( isWhiteSpace( pszBuf[uiCurrentChar]) ||
			  (pszBuf[uiCurrentChar] == '=') || 
			  (pszBuf[uiCurrentChar] == '#'))
		{
			pszNameEnd = &pszBuf[uiCurrentChar-1];
			break;
		}

		uiCurrentChar++;
	}

	if( (uiCurrentChar == uiNumBytes) && 
		  (pszNameEnd == NULL) )
	{
		pszNameEnd = &pszBuf[uiCurrentChar - 1];
	}

	// Now, there may be a value part or a comment part next.  If there's a
	// value, it had better be preceeded by an '='
	
	while( (uiCurrentChar < uiNumBytes) && 
			  isWhiteSpace( pszBuf[uiCurrentChar]) )
	{
		uiCurrentChar++;
	}
	
	if( uiCurrentChar < uiNumBytes && pszBuf[ uiCurrentChar] == '#')
	{
		goto Comment;
	}

	if( uiCurrentChar < uiNumBytes && pszBuf[uiCurrentChar] != '=' )
	{
		rc = RC_SET( NE_FLM_SYNTAX);
		goto Exit;
	}

	// Ok - at this point pszBuf[uiCurrentChar] contains an =.  Skip over
	// the = and any whitespace that follows.
	
	while( uiCurrentChar < uiNumBytes)
	{
		uiCurrentChar++;
		if( !isWhiteSpace( pszBuf[uiCurrentChar]))
		{
			pszValStart = &pszBuf[uiCurrentChar];
			break;
		}
	}

	// Now mark the end of the value.
	// We determine the end by looking for whitespace or '#'
	
	while( uiCurrentChar < uiNumBytes) 
	{
		if( isWhiteSpace( pszBuf[uiCurrentChar]) || 
			  (pszBuf[uiCurrentChar] == '#'))
		{
			pszValEnd = &pszBuf[uiCurrentChar-1];
			break;
		}		
		uiCurrentChar++;
	}

	if( uiCurrentChar == uiNumBytes && !pszValEnd)
	{
		pszValEnd = &pszBuf[uiCurrentChar-1];
	}

Comment:

	// Check out the rest of the line to see if there's a comment
	
	while( uiCurrentChar < uiNumBytes)
	{
		if( !isWhiteSpace( pszBuf[ uiCurrentChar]) &&
			 pszBuf[ uiCurrentChar] != '#')
		{
			rc = RC_SET( NE_FLM_SYNTAX);
			goto Exit;
		}
		else if( pszBuf[ uiCurrentChar] == '#')
		{
			// Comment found.  Set pszCommentStart to the next char
			
			pszCommentStart = &pszBuf[uiCurrentChar+1];
			break;
		}
		uiCurrentChar++;
	}

	// Done parsing.  Now, assuming the line had any info in it,
	// store all the strings...
	
	if( pszNameStart || pszCommentStart)
	{
		if( RC_BAD( rc = m_pool.poolCalloc( sizeof( INI_LINE),
										(void **)&pLine)))
		{
			goto Exit;
		}
		
		if( pszNameStart)
		{
			uiStrLen = pszNameEnd - pszNameStart + 1;
			if( RC_BAD( rc = m_pool.poolAlloc( uiStrLen + 1,
								(void **)&pLine->pszParamName)))
			{
				goto Exit;
			}
			
			f_memcpy( pLine->pszParamName, pszNameStart, uiStrLen);
			pLine->pszParamName[uiStrLen] = '\0';
		}

		if( pszValStart)
		{
			uiStrLen = pszValEnd - pszValStart + 1;
			if( RC_BAD( rc = m_pool.poolAlloc( uiStrLen + 1,
						(void **)&pLine->pszParamValue)))
			{
				goto Exit;
			}
			
			f_memcpy(pLine->pszParamValue, pszValStart, uiStrLen);
			pLine->pszParamValue[uiStrLen] = '\0';
		}
		
		if (pszCommentStart)
		{
			uiStrLen = uiNumBytes-(pszCommentStart-pszBuf);
			if (RC_BAD( rc = m_pool.poolAlloc( uiStrLen + 1,
										(void **)&pLine->pszComment)))
			{
				goto Exit;
			}
			
			f_memcpy(pLine->pszComment, pszCommentStart, uiStrLen);
			pLine->pszComment[uiStrLen] = '\0';
		}
		
		// Insert this struct into the linked list
		
		if( m_pLastLine)
		{
			m_pLastLine->pNext = pLine;
		}
		
		pLine->pPrev = m_pLastLine;
		pLine->pNext = NULL;
		m_pLastLine = pLine;
		
		if( !m_pFirstLine)
		{
			m_pFirstLine = pLine;
		}
	}
	
Exit:

	return( rc);
}
コード例 #27
0
/****************************************************************************
Desc:	Build a collated key value piece.
****************************************************************************/
RCODE KYCollateValue(
	FLMBYTE *			pucDest,
	FLMUINT *			puiDestLen,
	IF_PosIStream *	pIStream,
	FLMUINT				uiDataType,
	FLMUINT				uiFlags,
	FLMUINT				uiCompareRules,
	FLMUINT				uiLimit,
	FLMUINT *			puiCollationLen,
	FLMUINT *			puiLuLen,
	FLMUINT				uiLanguage,
	FLMBOOL				bFirstSubstring,
	FLMBOOL				bDataTruncated,
	FLMBOOL *			pbDataTruncated,
	FLMBOOL *			pbOriginalCharsLost)
{
	RCODE						rc = NE_XFLM_OK;
	FLMUINT					uiDestLen;
	IF_BufferIStream *	pBufferIStream = NULL;
	FLMUINT					uiCharLimit;
	FLMUINT					uiLength;
	FLMBYTE *				pucTmpDest;
	FLMUINT					uiBytesRead;
	FLMBOOL					bHaveData = TRUE;
	FLMUNICODE				uChar;
	FLMBYTE					ucDynaBuf[ 64];
	F_DynaBuf				dynaBuf( ucDynaBuf, sizeof( ucDynaBuf));

	if (puiLuLen)
	{
		*puiLuLen = 0;
	}

	if ((uiDestLen = *puiDestLen) == 0)
	{
		rc = RC_SET( NE_XFLM_KEY_OVERFLOW);
		goto Exit;
	}

	if (uiDataType != XFLM_TEXT_TYPE)
	{
		if( !pIStream->remainingSize())
		{
			bHaveData = FALSE;
		}
	}
	else
	{
		FLMUINT64	ui64SavePosition = pIStream->getCurrPosition();

		if( RC_BAD( rc = f_readUTF8CharAsUnicode( 
			pIStream, &uChar)))
		{
			if (rc == NE_XFLM_EOF_HIT)
			{
				bHaveData = FALSE;
				rc = NE_XFLM_OK;
			}
			else
			{
				goto Exit;
			}
		}

		if( RC_BAD( rc = pIStream->positionTo( ui64SavePosition)))
		{
			goto Exit;
		}

		// The text is expected to be 0-terminated UTF-8

		if ((uiFlags & ICD_ESC_CHAR) ||
			 (uiCompareRules &
				(XFLM_COMP_COMPRESS_WHITESPACE |
				 XFLM_COMP_NO_WHITESPACE |
				 XFLM_COMP_NO_UNDERSCORES |
				 XFLM_COMP_NO_DASHES |
				 XFLM_COMP_WHITESPACE_AS_SPACE |
				 XFLM_COMP_IGNORE_LEADING_SPACE |
				 XFLM_COMP_IGNORE_TRAILING_SPACE)))
		{
			dynaBuf.truncateData( 0);
			if (RC_BAD( rc = KYFormatUTF8Text( pIStream,
					uiFlags, uiCompareRules, &dynaBuf)))
			{
				goto Exit;
			}
			
			if( RC_BAD( rc = FlmAllocBufferIStream( &pBufferIStream)))
			{
				goto Exit;
			}
			
			if (RC_BAD( rc = pBufferIStream->openStream( 
				(const char *)dynaBuf.getBufferPtr(), dynaBuf.getDataLength())))
			{
				goto Exit;
			}
			pIStream = pBufferIStream;
		}

		uiCharLimit = uiLimit ? uiLimit : ICD_DEFAULT_LIMIT;

		if( (uiLanguage >= FLM_FIRST_DBCS_LANG ) && 
			 (uiLanguage <= FLM_LAST_DBCS_LANG))
		{
			if( RC_BAD( rc = f_asiaUTF8ToColText( pIStream, pucDest, &uiDestLen,
								(uiCompareRules & XFLM_COMP_CASE_INSENSITIVE)
								? TRUE
								: FALSE,
								puiCollationLen, puiLuLen,
								uiCharLimit, bFirstSubstring,
								bDataTruncated, pbDataTruncated)))
			{
				goto Exit;
			}
		}
		else
		{
			if( RC_BAD( rc = flmUTF8ToColText( pIStream, pucDest, &uiDestLen,
								(uiCompareRules & XFLM_COMP_CASE_INSENSITIVE)
								? TRUE
								: FALSE,
								puiCollationLen, puiLuLen,
								uiLanguage, uiCharLimit, bFirstSubstring,
								bDataTruncated,
								pbOriginalCharsLost, pbDataTruncated)))
			{
				goto Exit;
			}
		}
	}

	// TRICKY: uiDestLen could be set to zero if text and no value.

	if (!bHaveData || !uiDestLen)
	{
		uiDestLen = 0;
		goto Exit;
	}

 	switch (uiDataType)
	{
		case XFLM_TEXT_TYPE:
			break;

		case XFLM_NUMBER_TYPE:
		{
			FLMBYTE	ucTmpBuf [FLM_MAX_NUM_BUF_SIZE];
			
			uiLength = (FLMUINT)pIStream->remainingSize();
			
			flmAssert( uiLength <= sizeof( ucTmpBuf));

			if (RC_BAD( rc = pIStream->read( ucTmpBuf, uiLength, &uiBytesRead)))
			{
				goto Exit;
			}
			flmAssert( uiBytesRead == uiLength);
			if (RC_BAD( rc = flmStorageNum2CollationNum( ucTmpBuf,
										uiBytesRead, pucDest, &uiDestLen)))
			{
				goto Exit;
			}
			break;
		}

		case XFLM_BINARY_TYPE:
		{
			uiLength = (FLMUINT)pIStream->remainingSize();
			pucTmpDest = pucDest;

			if (uiLength >= uiLimit)
			{
				uiLength = uiLimit;
				bDataTruncated = TRUE;
			}

			// We don't want any single key piece to "pig out" more
			// than 256 bytes of the key

			if (uiDestLen > 256)
			{
				uiDestLen = 256;
			}

			if (uiLength > uiDestLen)
			{

				// Compute length so will not overflow

				uiLength = uiDestLen;
				bDataTruncated = TRUE;
			}
			else
			{
				uiDestLen = uiLength;
			}

			// Store as is.

			if (RC_BAD( rc = pIStream->read( pucTmpDest, uiDestLen, &uiBytesRead)))
			{
				goto Exit;
			}

			if (bDataTruncated && pbDataTruncated)
			{
				*pbDataTruncated = TRUE;
			}
			break;
		}

		default:
		{
			rc = RC_SET( NE_XFLM_CANNOT_INDEX_DATA_TYPE);
			break;
		}
	}

Exit:

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

	*puiDestLen = uiDestLen;
	return( rc);
}
コード例 #28
0
/**************************************************************************
Desc:		Get the Flaim collating string and convert back to a text string
Ret:		Length of new wpStr
Notes:	Allocates the area for the word string buffer if will be over 256.
***************************************************************************/
RCODE flmColText2StorageText(
	const FLMBYTE *	pucColStr,				// Points to the collated string
	FLMUINT				uiColStrLen,			// Length of the collated string
	FLMBYTE *			pucStorageBuf,			// Output string to build - TEXT string
	FLMUINT *			puiStorageLen,			// In: Size of buffer, Out: Bytes used
	FLMUINT	   		uiLang,
	FLMBOOL *			pbDataTruncated,		// Sets to TRUE if data had been truncated
	FLMBOOL *			pbFirstSubstring)		// Sets to TRUE if first substring
{
#define LOCAL_CHARS		150
	FLMBYTE		ucWPStr[ LOCAL_CHARS * 2 + LOCAL_CHARS / 5 ];	// Sample + 20%
	FLMBYTE *  	pucWPPtr = NULL;
	FLMBYTE *	pucAllocatedWSPtr = NULL;
	FLMUINT		uiWPStrLen;
	FLMBYTE *	pucStoragePtr;
	FLMUINT		uiUnconvChars;
	FLMUINT		uiTmp;
	FLMUINT		uiMaxStorageBytes = *puiStorageLen;
	FLMUINT		uiMaxWPBytes;
	FLMUINT		uiStorageOffset;
	FLMBYTE		ucTmpSen[ 5];
	FLMBYTE *	pucTmpSen = &ucTmpSen[ 0];
	RCODE			rc = NE_FLM_OK;

	if( uiColStrLen > LOCAL_CHARS)
	{
		// If it won't fit, allocate a new buffer

		if( RC_BAD( rc = f_alloc( SFLM_MAX_KEY_SIZE * 2, &pucWPPtr)))
		{
			goto Exit;
		}

		pucAllocatedWSPtr = pucWPPtr;
		uiMaxWPBytes = uiWPStrLen = SFLM_MAX_KEY_SIZE * 2;
	}
	else
	{
		pucWPPtr = &ucWPStr[ 0];
		uiMaxWPBytes = uiWPStrLen = sizeof( ucWPStr);
	}

 	if( (uiLang >= FLM_FIRST_DBCS_LANG) &&
 		 (uiLang <= FLM_LAST_DBCS_LANG))
 	{
		if( RC_BAD( rc = f_asiaColStr2WPStr( pucColStr, uiColStrLen,
			pucWPPtr, &uiWPStrLen, &uiUnconvChars,
			pbDataTruncated, pbFirstSubstring)))
		{
			goto Exit;
		}
	}
	else
	{
		if( RC_BAD( rc = f_colStr2WPStr( pucColStr, uiColStrLen,
			pucWPPtr, &uiWPStrLen, uiLang, &uiUnconvChars,
			pbDataTruncated, pbFirstSubstring)))
		{
			goto Exit;
		}
	}

	// Copy word string to the storage string area

	uiWPStrLen >>= 1;	// Convert # of bytes to # of words
	pucStoragePtr = pucStorageBuf;
	uiStorageOffset = 0;

	// Encode the number of characters as a SEN.  If pucEncPtr is
	// NULL, the caller is only interested in the length of the encoded
	// string, so a temporary buffer is used to call f_encodeSEN.

	uiTmp = f_encodeSEN( uiWPStrLen - uiUnconvChars, &pucTmpSen);
	if( (uiStorageOffset + uiTmp) >= uiMaxStorageBytes)
	{
		rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
		goto Exit;
	}
	f_memcpy( pucStoragePtr, &ucTmpSen[ 0], uiTmp);
	uiStorageOffset += uiTmp;

	// Encode each of the WP characters into UTF-8

	while( uiWPStrLen--)
	{
		FLMBYTE			ucChar;
		FLMBYTE			ucCharSet;
		FLMUNICODE		uChar;

		// Put the character in a local variable for speed

		ucChar = *pucWPPtr++;
		ucCharSet = *pucWPPtr++;

		if( ucCharSet == 0xFF && ucChar == 0xFF)
		{
			uChar = (((FLMUNICODE)*(pucWPPtr + 1)) << 8) | *pucWPPtr;
			pucWPPtr += 2;
			uiWPStrLen--; // Skip past 4 bytes for UNICODE
		}
		else
		{
			if( RC_BAD( rc = f_wpToUnicode(
				(((FLMUINT16)ucCharSet) << 8) + ucChar, &uChar)))
			{
				goto Exit;
			}
		}

		uiTmp = uiMaxStorageBytes - uiStorageOffset;
		if( RC_BAD( rc = f_uni2UTF8( uChar,
			&pucStorageBuf[ uiStorageOffset], &uiTmp)))
		{
			goto Exit;
		}
		uiStorageOffset += uiTmp;
	}

	if( uiStorageOffset >= uiMaxStorageBytes)
	{
		rc = RC_SET( NE_FLM_CONV_DEST_OVERFLOW);
		goto Exit;
	}

	// Tack on a trailing NULL byte

	pucStorageBuf[ uiStorageOffset++] = 0;

	// Return the length of the storage buffer

	*puiStorageLen = uiStorageOffset;

Exit:

	if( pucAllocatedWSPtr)
	{
		f_free( &pucAllocatedWSPtr);
	}

	return( rc);
}
コード例 #29
0
/*******************************************************************************
Desc:	Renames a database
*******************************************************************************/
FLMEXP RCODE FLMAPI FlmDbRename(
	const char *		pszDbName,
	const char *		pszDataDir,
	const char *		pszRflDir,
	const char *		pszNewDbName,
	FLMBOOL				bOverwriteDestOk,
	STATUS_HOOK			fnStatusCallback,
	void *				UserData)
{
	RCODE					rc = FERR_OK;
	IF_FileHdl *		pFileHdl = NULL;
	FLMUINT				uiFileNumber;
	FILE_HDR				FileHdr;
	LOG_HDR				LogHdr;
	DBRenameInfo *		pRenameList = NULL;
	FLMBOOL				bFileFound;
	FLMBYTE *			pucBuffer = NULL;
	FLMBYTE *			pucLogHdr;
	char *				pszOldName;
	char *				pszNewName;
	char *				pszOldDataName;
	char *				pszNewDataName;
	char *				pszFullNewName;
	char					szOldBase[ F_FILENAME_SIZE];
	char					szNewBase[ F_FILENAME_SIZE];
	char *				pszExtOld;
	char *				pszExtNew;
	char *				pszDataExtOld;
	char *				pszDataExtNew;

	// Cannot handle empty database name.

	flmAssert( pszDbName && *pszDbName);
	flmAssert( pszNewDbName && *pszNewDbName);

	// Allocate memory for a read buffer, the log header, and various
	// file names.

	if( RC_BAD( rc = f_allocAlignedBuffer( 
		2048 + LOG_HEADER_SIZE + F_PATH_MAX_SIZE * 5, &pucBuffer)))
	{
		goto Exit;
	}
	pucLogHdr = pucBuffer + 2048;
	pszOldName = (char *)(pucLogHdr + LOG_HEADER_SIZE);
	pszNewName = pszOldName + F_PATH_MAX_SIZE;
	pszOldDataName = pszNewName + F_PATH_MAX_SIZE;
	pszNewDataName = pszOldDataName + F_PATH_MAX_SIZE;
	pszFullNewName = pszNewDataName + F_PATH_MAX_SIZE;

	// There must be either no directory specified for the new name, or
	// it must be identical to the old directory.

	if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( 
		pszDbName, pszOldName, szOldBase)))
	{
		goto Exit;
	}
	
	if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathReduce( 
		pszNewDbName, pszNewName, szNewBase)))
	{
		goto Exit;
	}

	// Directories must be the same.

	if (*pszNewName && f_stricmp( pszOldName, pszNewName) != 0)
	{
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}
	
	f_strcpy( pszNewName, pszOldName);
	
	if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( 
		pszNewName, szNewBase)))
	{
		goto Exit;
	}

	f_strcpy( pszFullNewName, pszNewName);
	f_strcpy( pszOldName, pszDbName);

	if( pszDataDir && *pszDataDir)
	{
		f_strcpy( pszOldDataName, pszDataDir);
		f_strcpy( pszNewDataName, pszDataDir);
		
		if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( 
			pszOldDataName, szOldBase)))
		{
			goto Exit;
		}
		
		if (RC_BAD( rc = gv_FlmSysData.pFileSystem->pathAppend( 
			pszNewDataName, szNewBase)))
		{
			goto Exit;
		}
	}
	else
	{
		f_strcpy( pszNewDataName, pszNewName);
		f_strcpy( pszOldDataName, pszOldName);
	}

	// First make sure we have closed the databases and gotten rid of
	// them from our internal memory tables - in case they had been open.

	if( RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, 
		(void *)pszDbName, (void *)pszDataDir)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = FlmConfig( FLM_CLOSE_FILE, 
		(void *)pszFullNewName, (void *)pszDataDir)))
	{
		goto Exit;
	}
	
	gv_FlmSysData.pFileHdlCache->closeUnusedFiles();

	// Open the file so we can get the log header.

	if( RC_BAD( rc = gv_FlmSysData.pFileSystem->openFile( pszDbName, 
		gv_FlmSysData.uiFileOpenFlags, &pFileHdl)))
	{
		goto Exit;
	}

	// Read the header to get the low and high RFL log
	// file numbers.

	if (RC_BAD( flmReadAndVerifyHdrInfo( NULL, pFileHdl,
								pucBuffer, &FileHdr, &LogHdr, pucLogHdr)))
	{
		goto Exit;
	}

	// Close the file.

	pFileHdl->Release();
	pFileHdl = NULL;

	// Start renaming files, beginning with the main DB file.

	if( RC_BAD( rc = flmRenameFile( pszDbName, pszFullNewName,
								bOverwriteDestOk, FALSE,
								&pRenameList, &bFileFound,
								fnStatusCallback, UserData)))
	{
		goto Exit;
	}

	// Find where the extension of the old and new database names are

	pszExtOld = pszOldName + f_strlen( pszOldName) - 1;
	pszDataExtOld = pszOldDataName + f_strlen( pszOldDataName) - 1;
	while (pszExtOld != pszOldName && *pszExtOld != '.')
	{
		pszExtOld--;

		// Both the old db name and old data name have the same
		// base name, so we can decrement pszDataExtOld
		// at the same time we decrement pszExtOld.

		pszDataExtOld--;
	}
	
	if (*pszExtOld != '.')
	{
		pszExtOld = pszOldName + f_strlen( pszOldName);
		pszDataExtOld = pszOldDataName + f_strlen( pszOldDataName);
	}

	pszExtNew = pszNewName + f_strlen( pszNewName) - 1;
	pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName) - 1;
	
	while (pszExtNew != pszOldName && *pszExtNew != '.')
	{
		pszExtNew--;

		// Both the new db name and new data name have the same
		// base name, so we can decrement pszDataExtNew
		// at the same time we decrement pszExtNew.

		pszDataExtNew--;
	}
	
	if (*pszExtNew != '.')
	{
		pszExtNew = pszNewName + f_strlen( pszNewName);
		pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName);
	}

	// Rename the .lck file, if any.  This is necessary for UNIX.

	f_strcpy( pszExtOld, ".lck");
	f_strcpy( pszExtNew, ".lck");
	if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName,
								bOverwriteDestOk, TRUE,
								&pRenameList, &bFileFound,
								fnStatusCallback, UserData)))
	{
		goto Exit;
	}

	// Rename block (data) files.

	uiFileNumber = 1;
	for (;;)
	{
		F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum,
			uiFileNumber, pszDataExtOld);
		F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum,
			uiFileNumber, pszDataExtNew);

		if (RC_BAD( rc = flmRenameFile( pszOldDataName, pszNewDataName,
									bOverwriteDestOk, TRUE,
									&pRenameList, &bFileFound,
									fnStatusCallback, UserData)))
		{
			goto Exit;
		}
		if (!bFileFound)
		{
			break;
		}
		if (uiFileNumber ==
				MAX_DATA_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum))
		{
			break;
		}
		uiFileNumber++;
	}

	// Rename rollback log files.

	uiFileNumber =
			FIRST_LOG_BLOCK_FILE_NUMBER (FileHdr.uiVersionNum);
	for (;;)
	{
		F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum,
			uiFileNumber, pszExtOld);
		F_SuperFileClient::bldSuperFileExtension( FileHdr.uiVersionNum,
			uiFileNumber, pszExtNew);

		if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName,
									bOverwriteDestOk, TRUE,
									&pRenameList, &bFileFound,
									fnStatusCallback, UserData)))
		{
			goto Exit;
		}
		
		if (!bFileFound)
		{
			break;
		}
		
		if (uiFileNumber ==
				MAX_LOG_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum))
		{
			break;
		}
		
		uiFileNumber++;
	}

	// Rename roll-forward log files.

	if (FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3)
	{

		// For pre-4.3 versions, only need to rename one RFL file.

		if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum,
									pszDbName, pszRflDir, 1, pszOldName)))
		{
			goto Exit;
		}
		if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum,
									pszFullNewName, pszRflDir, 1, pszNewName)))
		{
			goto Exit;
		}
		if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName,
									bOverwriteDestOk, TRUE,
									&pRenameList, &bFileFound,
									fnStatusCallback, UserData)))
		{
			goto Exit;
		}
	}
	else
	{

		// For 4.3 and greater, rename the RFL directory.

		if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum,
									pszDbName, pszRflDir, pszOldName, szOldBase)))
		{
			goto Exit;
		}

		if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum,
									pszFullNewName, pszRflDir, pszNewName,
									szNewBase)))
		{
			goto Exit;
		}

		if (RC_BAD( rc = flmRenameFile( pszOldName, pszNewName,
									bOverwriteDestOk, TRUE,
									&pRenameList, &bFileFound,
									fnStatusCallback, UserData)))
		{
			goto Exit;
		}
	}

Exit:

	if( pFileHdl)
	{
		pFileHdl->Release();
	}
	
	if( pucBuffer)
	{
		f_freeAlignedBuffer( &pucBuffer);
	}

	// Free the list of renamed files.

	while( pRenameList)
	{
		DBRenameInfo *		pRenameFile;

		pRenameFile = pRenameList;
		pRenameList = pRenameList->pNext;

		// If we had an error of some sort, attempt to un-rename
		// the file that had been renamed.

		if (RC_BAD( rc))
		{
			gv_FlmSysData.pFileSystem->renameFile( 
				pRenameFile->Info.szDstFileName, pRenameFile->Info.szSrcFileName);
		}
		
		f_free( &pRenameFile);
	}
	
	return( rc);
}
コード例 #30
0
ファイル: fqstack.cpp プロジェクト: ajumi2/libflaim
/****************************************************************************
Desc : Adds an operator to the selection criteria of a given cursor.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmCursorAddOp(
	HFCURSOR		hCursor,
	QTYPES		eOperator,
	FLMBOOL		bResolveUnknown
	)
{
	RCODE			rc = FERR_OK;
	CURSOR *		pCursor = (CURSOR *)hCursor;
	FQNODE *		pTmpQNode;
	FQNODE *		pTmpGraftNode;
	FQNODE *		pTmpChildNode;
	FLMBOOL		bDecrementNestLvl = FALSE;
	FLMUINT		uiFlags = bResolveUnknown ? FLM_RESOLVE_UNK : 0;

	if (!pCursor)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}
	if (RC_BAD( rc = pCursor->rc))
	{
		goto Exit;
	}

	// If a read operation has already been performed on this query, no
	// selection criteria may be added.
	
	if (pCursor->bOptimized)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}
	
	// If the operator is a left paren, link it as the last sibling in the
	// argument list of the current operator.

	if (eOperator == FLM_LPAREN_OP)
	{
		(pCursor->QTInfo.uiNestLvl)++;
		goto Exit;
	}

	// If it is a right paren, find the left paren and close it out

	if (eOperator == FLM_RPAREN_OP)
	{
		if (!pCursor->QTInfo.uiNestLvl)
		{
			rc = RC_SET( FERR_CURSOR_SYNTAX);
			goto Exit;
		}
		(pCursor->QTInfo.uiNestLvl)--;
		goto Exit;
	}
		
	// If it is not an operator, return an error

	if (!IS_OP( eOperator))
	{
		rc = RC_SET( FERR_CURSOR_SYNTAX);
		goto Exit;
	}

	// If an operator is not expected, bail out

	if (!(pCursor->QTInfo.uiExpecting & FLM_Q_OPERATOR) &&
		 eOperator != FLM_NEG_OP &&
		 eOperator != FLM_NOT_OP)
	{
		rc = RC_SET( FERR_CURSOR_SYNTAX);
		goto Exit;
	}

	// Make a QNODE and find a place for it in the query tree

	if (RC_BAD( rc = flmCurMakeQNode( &pCursor->QueryPool, eOperator,
								NULL, 0, uiFlags, &pTmpQNode)))
	{
		goto Exit;
	}
	pTmpQNode->uiNestLvl = pCursor->QTInfo.uiNestLvl;

	// If this is the first operator in the query, set the current operator
	// to it and graft in the current operand as its child.  NOTE:  there
	// should always be a current operand at this point.

	if (!pCursor->QTInfo.pTopNode)
	{
		pCursor->QTInfo.pTopNode = pTmpQNode;
		pCursor->QTInfo.pCurOpNode = pTmpQNode;
		if (pCursor->QTInfo.pCurAtomNode)
		{

			// If the current operand node is a user predicate, the only
			// thing that can become its parent is a logical operator.

			if (GET_QNODE_TYPE( pCursor->QTInfo.pCurAtomNode) ==
				 FLM_USER_PREDICATE && !IS_LOG_OP( eOperator))
			{
				rc = RC_SET( FERR_CURSOR_SYNTAX);
				goto Exit;
			}
			flmCurLinkLastChild( pTmpQNode, pCursor->QTInfo.pCurAtomNode);
		}
		pCursor->QTInfo.uiExpecting = FLM_Q_OPERAND;
		goto Exit;
	}

	// Go up the stack until an operator whose nest level or precedence is < 
	// this one's is encountered, then link this one in as the last child

	for (pTmpChildNode = NULL, pTmpGraftNode = pCursor->QTInfo.pCurOpNode;
				;
		  pTmpChildNode = pTmpGraftNode, pTmpGraftNode = pTmpGraftNode->pParent)
	{
		if (pTmpGraftNode->uiNestLvl < pTmpQNode->uiNestLvl ||
			 (pTmpGraftNode->uiNestLvl == pTmpQNode->uiNestLvl &&
			  PRECEDENCE( pTmpGraftNode->eOpType) < PRECEDENCE( eOperator)))
		{

			// If the node under which this operator is to be grafted already
			//	has two children, or if its child is at a greater nesting level,
			//	link the child as the last child of this operator.  Example:
			//	((A - B) == C) && (((D + E) * F) == G).
			//	When the '*' operator in this expression is added, it will be
			//	grafted as the last child of the '&&' operator.  But the '+'
			//	must first be unlinked from the '&&' and then linked as the child
			//	of the '*'.  Otherwise, they will be siblings, and the expression
			//	will be evaluated incorrectly.

			if (pTmpChildNode &&
				 (pTmpChildNode->uiNestLvl > pTmpQNode->uiNestLvl ||
				  pTmpChildNode->pPrevSib != NULL ||
				  pTmpGraftNode->eOpType == FLM_NEG_OP ||
				  pTmpGraftNode->eOpType == FLM_NOT_OP))
			{
				flmCurLinkLastChild( pTmpQNode, pTmpChildNode);
			}

			// If this operator is to be grafted into the query tree at the leaf
			//	level, link the current operand as its last child.  Examples:
			//	in A * (B + C), we want B to be linked to +;
			//	in A + B * C, we want B linked to *.

			if (pTmpGraftNode == pCursor->QTInfo.pCurOpNode &&
				 eOperator != FLM_NEG_OP &&
				 eOperator != FLM_NOT_OP)
			{

				// If the current operand node is a user predicate, the only
				// thing that can become its parent is a logical operator.

				if (pCursor->QTInfo.pCurAtomNode &&
					 GET_QNODE_TYPE( pCursor->QTInfo.pCurAtomNode) ==
						FLM_USER_PREDICATE && !IS_LOG_OP( eOperator))
				{
					rc = RC_SET( FERR_CURSOR_SYNTAX);
					goto Exit;
				}
				flmCurLinkLastChild( pTmpQNode, pCursor->QTInfo.pCurAtomNode);
			}
			flmCurLinkLastChild( pTmpGraftNode, pTmpQNode);
			break;
		}
		if (!pTmpGraftNode->pParent)
		{
			pCursor->QTInfo.pTopNode = pTmpQNode;
			flmCurLinkLastChild( pTmpQNode, pTmpGraftNode);
			break;
		}
	}

	pCursor->QTInfo.pCurOpNode = pTmpQNode;
	pCursor->QTInfo.uiExpecting = FLM_Q_OPERAND;

Exit:
	if (bDecrementNestLvl)
	{
		(pCursor->QTInfo.uiNestLvl)--;
	}
	if (pCursor)
	{
		pCursor->rc = rc;
	}
	return( rc);
}