Пример #1
0
CSPStoreObject *CSPStore::CreateObject(FLMUNICODE *pName, FLMUNICODE *pId, FLMUNICODE *pType, FLMBOOL *pNewObject, FLMINT flmId)
{
	FlmRecord			*pRec = NULL;
	CSPStoreObject		*pObject = NULL;


	// Make sure the object does not exist.
	pRec = FindObject(pId);

	if (pRec)
	{
		//if (openExisting)
		{
			FLMUINT drn = pRec->getID();
			pRec->clear();
			pRec->setID(drn);
			pObject = new CSPStoreObject(this, pName, pId, pType, pRec);
			*pNewObject = 0;
		}
		//else
		//{
		//	pRec->Release();
		//	pRec = NULL;
		//	return (pObject);
		//}
	}
	else
	{
		pObject = new CSPStoreObject(this, pName, pId, pType, flmId);
		*pNewObject = 1;
	}

	return (pObject);
} // CSPStore::CreateObject()
Пример #2
0
RCODE CSPStore::DeleteObject(FLMUNICODE *pId, int *pFlmId)
{
	CSPStoreObject	*pObject;
	FlmRecord		*pRec;
	RCODE			rc = FERR_NOT_FOUND;

	pRec = FindObject(pId);
	if (pRec)
	{
		*pFlmId = pRec->getID();
		pObject = new CSPStoreObject(this, pRec);
		pObject->Delete();
		rc = pObject->Flush();
		delete pObject;
	}
	return (rc);
} // CSPStore::DeleteObject()
Пример #3
0
FlmRecord * CSPStore::FindObject(FLMUNICODE *pId)
{
	RCODE			rc = FERR_OK;
	HFCURSOR		cursor = 0;
	FlmRecord	*pRec = NULL;
	FlmRecord	*pRWRec = NULL;
	FLMUINT		fieldId;
	FLMUINT		count;

	rc = NameToId(CS_Name_GUID, &fieldId);
	if (RC_OK(rc))
	{
		rc = FlmCursorInit(m_hFlaim, FLM_DATA_CONTAINER, &cursor);
		if (RC_OK(rc))
		{
			rc = FlmCursorAddField(cursor, fieldId, 0);
			if (RC_OK(rc))
			{
				rc = FlmCursorAddOp(cursor, FLM_EQ_OP, 0);
				if (RC_OK(rc))
				{
					rc = FlmCursorAddValue(cursor, FLM_UNICODE_VAL, pId, 0);
					if (RC_OK(rc))
					{
						rc = FlmCursorRecCount(cursor, &count);
						if (RC_OK(rc) && count != 0)
						{
							rc = FlmCursorNext(cursor, &pRec);
							if (RC_OK(rc))
							{
								pRWRec = pRec->copy();
								pRec->Release();
								pRec = NULL;
							}
						}
					}
				}
			}
			FlmCursorFree(&cursor);
		}
	}
	return (pRWRec);
} // CSPStore::FindObject()
Пример #4
0
RCODE CSPDB::RegisterField(HFDB hFlaim, FLMUNICODE *pFieldName, FLMUINT flmType, FLMUINT* pFieldId)
{
	RCODE				rc = FERR_OK;
	FlmRecord			*pRec = NULL;
	void				*pvField = 0;

	pRec = new FlmRecord();
	if (pRec != NULL)
	{
		rc = pRec->insertLast(0, FLM_FIELD_TAG, FLM_TEXT_TYPE, &pvField);
		if (RC_OK(rc))
		{
			rc = pRec->setUnicode(pvField, (FLMUNICODE*)pFieldName);
			if (RC_OK(rc))
			{
				rc = pRec->insert(pvField, INSERT_LAST_CHILD, FLM_TYPE_TAG, FLM_TEXT_TYPE, &pvField);
				if (RC_OK(rc))
				{
					if (flmType != FLM_UNDEFINED_TYPE)
					{
						rc = pRec->setUnicode(pvField, (FLMUNICODE*)cs_flaim_type_name[flmType]);
						if (RC_OK(rc))
						{
							rc = FlmRecordAdd(hFlaim, FLM_DICT_CONTAINER, pFieldId, pRec, 0);
							if (RC_OK(rc))
							{
								rc = m_NameTable.addTag((FLMUNICODE*)pFieldName, 0, *pFieldId, 0, 0, TRUE);
							}
						}
					}
					else
					{
						rc = FERR_BAD_FIELD_TYPE;
					}
				}
			}
		}
		pRec->Release();
	}
	else
	{
		rc = FERR_MEM;
	}

	return (rc);
} // CSPDB::registerField()
Пример #5
0
/****************************************************************************
Desc:		Thread that will build an index in the background.
			Caller will create a pDb to use.  This pDb must be
			freed at the conclusion of the routine.
****************************************************************************/
FSTATIC RCODE FLMAPI flmBackgroundIndexBuildThrd(
	IF_Thread *			pThread)
{
	RCODE					rc = FERR_OK;
	IXD *					pIxd;
	F_BKGND_IX * 		pBackgroundIx = (F_BKGND_IX *)pThread->getParm1();
	FLMBOOL				bStartedTrans;
	FLMBOOL				bDbInitialized;
	FLMUINT				uiContainerNum;
	FLMUINT				uiFirstDrn;
	FLMUINT				uiIndexNum;
	FDB *					pDb = NULL;
	FLMBOOL				bForcedShutdown = FALSE;
	FLMBOOL				bHitEnd;
	FINDEX_STATUS		savedIxStatus;
	FlmRecord *			pReusableRec = NULL;
	char					szMsg[ 128];
	FLMINT				iErrorLine = 0;
	FLMBOOL				bLimitedMode = FALSE;

	pThread->setThreadStatus( FLM_THREAD_STATUS_INITIALIZING);

	if( (pReusableRec = f_new FlmRecord) != NULL)
	{
		if( RC_BAD( pReusableRec->preallocSpace( 512, 1024 * 64)))
		{
			pReusableRec->Release();
			pReusableRec = NULL;
		}
	}

Loop_Again:

	rc = FERR_OK;
	uiIndexNum = pBackgroundIx->indexStatus.uiIndexNum;
	flmAssert( pThread->getThreadAppId() == uiIndexNum);
	bDbInitialized = FALSE;
	bStartedTrans = FALSE;
	pDb = NULL;

	// We could loop forever on flmOpenFile errors, check if we should exit.

	if( pThread->getShutdownFlag())
	{
		bForcedShutdown = TRUE;
		goto Exit;
	}

	if( RC_BAD( rc = flmOpenFile( pBackgroundIx->pFile,
		NULL, NULL, NULL, 0, TRUE, NULL, NULL,
		pBackgroundIx->pFile->pszDbPassword, &pDb)))
	{

		// If the file is being closed, this is not an error.

		if( pBackgroundIx->pFile->uiFlags & DBF_BEING_CLOSED)
		{
			bForcedShutdown = TRUE;
			rc = FERR_OK;
		}
		else
		{
			iErrorLine = (FLMINT)__LINE__;
		}
		goto Exit;
	}

	flmAssert( pDb->pSFileHdl);

	bDbInitialized = TRUE;
	if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, 0, 0, &bStartedTrans)))
	{
		iErrorLine = (FLMINT)__LINE__;
		goto Exit;
	}
	flmAssert( !bStartedTrans);
	pDb->uiFlags |= FDB_BACKGROUND_INDEXING;

	for(;;)
	{
		// Set the thread's status

		pThread->setThreadStatus( FLM_THREAD_STATUS_RUNNING);

		// See if we should shut down. 

		if( pThread->getShutdownFlag())
		{
			bForcedShutdown = TRUE;
			break;
		}

		// Obtain the file lock

		flmAssert( !(pDb->uiFlags & FDB_HAS_FILE_LOCK));
		if( RC_BAD( rc = pDb->pFile->pFileLockObj->lock( pDb->hWaitSem,  
			TRUE, FLM_NO_TIMEOUT, FLM_BACKGROUND_LOCK_PRIORITY,
			pDb->pDbStats ? &pDb->pDbStats->LockStats : NULL)))
		{
			if( rc == FERR_IO_FILE_LOCK_ERR)
			{
				// This would only happen if we were signaled to shut down.
				// So, it's ok to exit

				flmAssert( pThread->getShutdownFlag());
				bForcedShutdown = TRUE;
				rc = FERR_OK;
			}
			else
			{
				iErrorLine = (FLMINT)__LINE__;
			}
			goto Exit;
		}

		// The lock needs to be marked as implicit so that flmCommitDbTrans
		// will unlock the file and allow the next update transaction to
		// begin before all writes are complete.

		pDb->uiFlags |= (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT);

		// If there are higher priority waiters in the lock queue,
		// or we are being told to shut down, we want to relinquish.

		if( pThread->getShutdownFlag() ||
			pDb->pFile->pFileLockObj->haveHigherPriorityWaiter( 
				FLM_BACKGROUND_LOCK_PRIORITY))
		{
			if (RC_BAD( rc = pDb->pFile->pFileLockObj->unlock()))
			{
				iErrorLine = (FLMINT)__LINE__;
				goto Exit;
			}

			pDb->uiFlags &= ~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT);
			continue;
		}

		// Start an update transaction 

		if( RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, FLM_NO_TIMEOUT, 
			FLM_DONT_POISON_CACHE)))
		{
			if( rc == FERR_IO_FILE_LOCK_ERR)
			{
				// This would only happen if we were signaled to shut down.
				// So, it's ok to exit

				flmAssert( pThread->getShutdownFlag());
				bForcedShutdown = TRUE;
				rc = FERR_OK;
			}
			else
			{
				iErrorLine = (FLMINT)__LINE__;
			}
			goto Exit;
		}
		bStartedTrans = TRUE;

		if( RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode,
			uiIndexNum, NULL, &pIxd, TRUE)))
		{
			// Index may have been deleted by another transaction, or
			// there may have been some other error.

			iErrorLine = (FLMINT)__LINE__;
			goto Exit;
		}

		// If we're running in limited mode, then we can't mess with encrypted
		// indexes.  On the other hand, since the index is marked as offline,
		// but not suspended, this thread has to exist, or else it will cause
		// all kinds of problems elsewhere.  So, in such a case, we will simply
		// sleep in an inifinite loop until the shutdown flag is set.
		// (We consider this acceptable becase running in limited mode is not
		// the norm, and Flaim probably won't be up for very long in this mode.)

		if( pDb->pFile->bInLimitedMode && pIxd->uiEncId)
		{
			bLimitedMode = TRUE;
			goto Exit;
		}

		// Look up the tracker info to determine where we need to being indexing

		if (RC_BAD( rc = flmGetIxTrackerInfo( pDb,
			pBackgroundIx->indexStatus.uiIndexNum, &uiContainerNum,
			&uiFirstDrn, NULL, &pBackgroundIx->indexStatus.bSuspended)))
		{
			iErrorLine = (FLMINT)__LINE__;
			goto Exit;
		}

		// If the index is suspended, this thread should have been
		// shut down.  The suspending thread will keep the database
		// locked until we exit.  So, if we have the database locked,
		// the index better not be suspended.

		flmAssert( !pBackgroundIx->indexStatus.bSuspended &&
			!(pIxd->uiFlags & IXD_SUSPENDED));

		if (pIxd->uiContainerNum)
		{
			uiContainerNum = pIxd->uiContainerNum;
			if( uiFirstDrn == DRN_LAST_MARKER)
			{
				goto Exit;
			}
		}
		else
		{
			if( uiFirstDrn == DRN_LAST_MARKER && uiContainerNum == 0xFFFFFFFF)
			{
				goto Exit;
			}
			else
			{
				// The container number from the tracker record
				// may not be a real container.
				// Determine what the next actual container number is.

				if (uiContainerNum != FLM_DATA_CONTAINER)
				{
					while( uiContainerNum < pDb->pDict->uiIttCnt)
					{
						ITT *	pItt = &pDb->pDict->pIttTbl [uiContainerNum];
						if (ITT_IS_CONTAINER( pItt))
						{
							break;
						}
						else
						{
							uiContainerNum++;
						}
					}

					if (uiContainerNum >= pDb->pDict->uiIttCnt)
					{
						uiContainerNum = FLM_DATA_CONTAINER;
					}
				}
			}
		}

		// Setup the DRN range we want to index.

		uiFirstDrn++;
		flmAssert( pIxd->uiLastDrnIndexed == uiFirstDrn - 1);

		// Set the thread's status

		pThread->setThreadStatus( "Indexing %u:%u", 
			(unsigned)uiContainerNum, (unsigned)uiFirstDrn);

		// Read and index up to the highest drn (or record higher than uiEndDrn)
		// or until time runs out.  The 500 is millisecs to take for the transaction.

		f_memcpy( &savedIxStatus, 
			&pBackgroundIx->indexStatus, sizeof( FINDEX_STATUS));

		if( RC_BAD( rc = flmIndexSetOfRecords( pDb,
			uiIndexNum, uiContainerNum, uiFirstDrn, DRN_LAST_MARKER,
			NULL, NULL, NULL, NULL,
			&pBackgroundIx->indexStatus, &bHitEnd, pThread, pReusableRec)))
		{
			// Lock the mutex while copying the saved index status back to
			// the main index status so that someone requesting the index status
			// won't see the status while the memcpy is in progress.

			f_mutexLock( gv_FlmSysData.hShareMutex);
			f_memcpy( &pBackgroundIx->indexStatus, 
				&savedIxStatus, sizeof( FINDEX_STATUS));
			f_mutexUnlock( gv_FlmSysData.hShareMutex);
			iErrorLine = (FLMINT)__LINE__;
			goto Exit;
		}

		if( pBackgroundIx->indexStatus.uiRecordsProcessed - 
			savedIxStatus.uiRecordsProcessed)
		{
			if( RC_BAD( rc = pDb->pFile->pRfl->logIndexSet( uiIndexNum,
						uiContainerNum, uiFirstDrn, 
						pBackgroundIx->indexStatus.uiLastRecordIdIndexed)))
			{
				iErrorLine = (FLMINT)__LINE__;
				goto Exit;
			}
		}

		// Commit the transaction (even if we didn't do any indexing work).

		if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE)))
		{
			iErrorLine = (FLMINT)__LINE__;
			goto Exit;
		}

		bStartedTrans = FALSE;
		pBackgroundIx->indexStatus.uiTransactions++;

		if( bHitEnd)
		{
			// flmIndexSetOfRecords brought the index on-line

			if( gv_FlmSysData.UpdateEvents.pEventCBList)
			{
				flmDoEventCallback( F_EVENT_UPDATES, 
						F_EVENT_INDEXING_COMPLETE, (void *)uiIndexNum, 
						(void *)0);
			}

			// Log a message

			flmLogIndexingProgress( uiIndexNum, 0);
			break;
		}
	}

Exit:

	pThread->setThreadStatus( FLM_THREAD_STATUS_TERMINATING);

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

	if( pDb && pDb->uiFlags & FDB_HAS_FILE_LOCK)
	{
		(void)pDb->pFile->pFileLockObj->unlock();
		pDb->uiFlags &= ~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT);
	}

	if( bDbInitialized)
	{
		fdbExit( pDb);
		bDbInitialized = FALSE;
	}

	if( pDb)
	{
		(void)FlmDbClose( (HFDB *) &pDb);
	}

	if( RC_BAD(rc) && !bForcedShutdown)
	{
		if (rc == FERR_MEM || rc == FERR_IO_DISK_FULL ||
			rc == FERR_MUST_WAIT_CHECKPOINT)
		{
			// Log the error

			f_sprintf( (char *)szMsg,
				"Background indexing thread %u (index %u)",
				(unsigned)pThread->getThreadId(), (unsigned)uiIndexNum);
			flmLogError( rc, (char *)szMsg, __FILE__, iErrorLine);

			// Sleep a half second and try again.

			pThread->sleep( 500);
			goto Loop_Again;
		}
		else
		{
			f_sprintf( (char *)szMsg,
				"Background indexing thread %u (index %u) -- unrecoverable error.",
				(unsigned)pThread->getThreadId(), (unsigned)uiIndexNum);
			flmLogError( rc, (char *)szMsg, __FILE__, iErrorLine);
		}
	}

	if( pReusableRec)
	{
		flmAssert( pReusableRec->getRefCount() == 1);
		pReusableRec->Release();
	}

	if( bLimitedMode)
	{
		flmAssert( RC_OK( rc));

		for (;;)
		{
			if( pThread->getShutdownFlag())
			{
				break;
			}

			pThread->sleep( 1000);
		}
	}

	// Set the thread's app ID to 0, so that it will not
	// be found now that the thread is terminating (we don't
	// want flmBackgroundIndexGet to find the thread).

	pThread->setThreadAppId( 0);

	// Free the background index structure

	f_mutexLock( gv_FlmSysData.hShareMutex);
	f_free( &pBackgroundIx);
	pThread->setParm1( NULL);
	f_mutexUnlock( gv_FlmSysData.hShareMutex);

	return( rc);
}
Пример #6
0
/************************************************************************
Desc : Deletes a record from a container.
Notes: This is the internal call that corresponds to FlmRecordDelete.
		 It may also be called by the database checking code when
		 repairing an index.
*************************************************************************/
RCODE	flmDeleteRecord(
	FDB *				pDb,					// Operation context
	LFILE *			pLFile,				// LFILE of container to delete from.
	FLMUINT			uiDrn,				// DRN of the record to be deleted.
	FlmRecord **	ppOldRecord,		// Returns old record, if not null.
	FLMBOOL			bMissingKeysOK		// Is it OK for keys to be missing in the
												// indexes that are to be updated?
												// should we report when index entries
												// aren't found? TRUE=don't report,
												// FALSE=do report.
	)
{
	RCODE				rc = FERR_OK;
	FlmRecord *		pOldRecord = NULL;
	FLMUINT			uiContainer = pLFile->uiLfNum;
	FLMUINT			uiAction;
	FLMBOOL			bHadUniqueKeys;
	FLMBOOL			bProcessedKeys = FALSE;

	if( pDb->uiFlags & FDB_COMMITTING_TRANS)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_TRANS_OP);
		goto Exit;
	}

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

	if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
		uiContainer, uiDrn, FALSE, NULL, NULL, &pOldRecord)))
	{
		if (rc != FERR_NOT_FOUND)
		{
			goto Exit;
		}
		
		if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, 
			&pOldRecord, NULL, NULL)))
		{
			goto Exit;
		}
	}

	if( uiContainer == FLM_LOCAL_DICT_CONTAINER )
	{
		if( RC_OK( rc = flmLFileDictUpdate( pDb, &pLFile, 
			&uiDrn, NULL, pOldRecord, FALSE, FALSE, NULL)))
		{
			rc = flmRcaRemoveRec( pDb, uiContainer, uiDrn);
		}
		
		goto Exit;
	}

	// First read the record, then delete it's keys and then it.

	uiAction = (FLMUINT)((bMissingKeysOK)
							  ? (FLMUINT)(KREF_DEL_KEYS | KREF_MISSING_KEYS_OK)
							  : (FLMUINT)(KREF_DEL_KEYS));
	bProcessedKeys = TRUE;
	bHadUniqueKeys = FALSE;
	if( RC_BAD(rc = flmProcessRecFlds( pDb, NULL, uiContainer,
													uiDrn, pOldRecord, uiAction,
													TRUE,
													&bHadUniqueKeys)))
	{
		goto Exit;
	}
	
	// NOTE: The LFile table may have changed locations if the dictionary 
	// was updated because of a change in a field state
	
	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}
	
	if( RC_BAD( rc = KYProcessDupKeys( pDb, bHadUniqueKeys)))
	{
		goto Exit;
	}
	
	if( RC_BAD( rc = FSRecUpdate( pDb, pLFile, NULL, uiDrn, REC_UPD_DELETE)))
	{
		goto Exit;
	}

	// Remove the record from cache

	if( RC_BAD( rc = flmRcaRemoveRec( pDb, uiContainer, uiDrn)))
	{
		(void)FSRecUpdate( pDb, pLFile, pOldRecord, uiDrn, REC_UPD_ADD);
		goto Exit;
	}

	// Don't make this call until we are sure of success - because we want to
	// be able to back things out of KREF table.

	KYFinishCurrentRecord( pDb);

Exit:

	if (RC_BAD( rc) && bProcessedKeys)
	{
		KYAbortCurrentRecord( pDb);
	}

	if( ppOldRecord)
	{
		*ppOldRecord = pOldRecord;
	}
	else if( pOldRecord)
	{
		pOldRecord->Release();
	}

	// Add the BLOB entries to the blob list.
	
	rc = FB_OperationEnd( pDb, rc);
	return( rc);
}
Пример #7
0
/****************************************************************************
Desc : Deletes a record from a container.
Notes: If an index definition record or a container definition record is
		 deleted from the dictionary container, the index B-TREE container or
		 container B-TREE will be deleted automatically when the transaction
		 commits.  Field definition records can only be deleted from the
		 dictionary using this routine if the field is not in use.  For more
		 information on deletion of field definitions, see the Dictionary Syntax
		 document.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmRecordDelete(
	HFDB	 		hDb,
	FLMUINT		uiContainer,
	FLMUINT		uiDrn,
	FLMUINT		uiAutoTrans
	)
{
	RCODE				rc = FERR_OK;
	LFILE *			pLFile;
	FDB *				pDb = (FDB *)hDb;
	FLMBOOL			bStartedAutoTrans;
	FlmRecord *		pOldRecord;
	FlmRecord **	ppOldRecord;
	DB_STATS *		pDbStats = NULL;
	F_TMSTAMP		StartTime;

	if( uiContainer == FLM_TRACKER_CONTAINER)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		rc = flmDoUpdateCS( pDb, FCS_OP_RECORD_DELETE, uiContainer,
									&uiDrn, NULL, uiAutoTrans);
		goto ExitCS;
	}

	bStartedAutoTrans = FALSE;
	pOldRecord = NULL;
	ppOldRecord = NULL;

	if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, FDB_TRANS_GOING_OK,
											uiAutoTrans, &bStartedAutoTrans)))
	{
		goto Exit;
	}

	if( (pDbStats = pDb->pDbStats) != NULL)
	{
		f_timeGetTimeStamp( &StartTime);
	}

	if( !uiDrn || uiDrn == (FLMUINT) DRN_LAST_MARKER)
	{
		rc = RC_SET( FERR_BAD_DRN);
		goto Exit;
	}

	if( RC_BAD(rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		// Do not have flmDeleteRecord fetch the old version of the record
		// unless an event callback is registered.
		
		ppOldRecord = &pOldRecord;
	}
	
	// NOTE: pLFile should NOT be used after this call, because flmDeleteRecord
	// could actually change its position in memory due to field changes.

	if (RC_BAD( rc = flmDeleteRecord( pDb, pLFile, uiDrn, ppOldRecord, FALSE)))
	{
		goto Exit;
	}

Exit:

	if( RC_OK( rc))
	{
		rc = pDb->pFile->pRfl->logUpdate( uiContainer, uiDrn, 
			uiAutoTrans, NULL, NULL);
	}

	if( pDbStats)
	{
		flmAddElapTime( &StartTime, &pDbStats->RecordDeletes.ui64ElapMilli);
		pDbStats->RecordDeletes.ui64Count++;
		pDbStats->bHaveStats = TRUE;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_DELETE_RECORD, hDb, rc, uiDrn,
								uiContainer, NULL, pOldRecord);
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, 
		pDb->LogHdr.uiCurrTransID, uiContainer, uiDrn, rc, "RDel");
#endif

	// If started an automatic transaction, end it.

	if( bStartedAutoTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}

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

ExitCS:

	flmExit( FLM_RECORD_DELETE, pDb, rc);

	return( rc);
}
Пример #8
0
/****************************************************************************
Desc : Modifies a record within a container.
Notes: If an index definition record is modified in the dictionary container,
		 the index B-TREE will be deleted and rebuilt automatically when the
		 transaction commits.  If an index definition record is changed into
		 a field definition record or a container definition record, the index
		 will be automatically deleted when the transaction commits.  When a
		 non-unique index is changed to a unique index, or the fields in a
		 unique index are changed, FLAIM needs to verify that each key in the
		 proposed index is indeed a unique key.  However, this verification
		 does NOT occur until the dictionary transaction commits and the
		 index is actually rebuilt.  If FLAIM discovers that the keys in the
		 proposed index are not unique, the transaction commit will fail and
		 return FERR_NOT_UNIQUE.

		 If a container definition record is changed into a field definition
		 record, the container will be deleted automatically when the
		 transaction commits.  If a container definition record is changed
		 into an index definition record, the container will be automatically
		 deleted and the index will be automatically built when the transaction
		 commits.

		 Only the name and state of field definition records can be modified.
		 Changing a field type or changing a field definition record into an
		 index definition record is not allowed.  For information on changing
		 the state of a field, see the Dictionary Syntax document.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmRecordModify(
	HFDB		   hDb,
	FLMUINT		uiContainer,
	FLMUINT		uiDrn,
	FlmRecord *	pRecord,
	FLMUINT		uiAutoTrans
	)
{
	RCODE			rc = FERR_OK;
	RCODE			rc1;
	FDB *			pDb = (FDB *)hDb;
	FlmRecord *	pOldRecord = NULL;
	LFILE *		pLFile;
	FLMBOOL		bStartedAutoTrans = FALSE;
	FLMBOOL		bProcessedKeys = FALSE;
	FLMBOOL		bLogCompleteIndexSet = FALSE;
	FLMBOOL		bHadUniqueKeys;
	DB_STATS *	pDbStats = NULL;
	F_TMSTAMP	StartTime;

	if( uiContainer == FLM_TRACKER_CONTAINER)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		rc = flmDoUpdateCS( pDb, FCS_OP_RECORD_MODIFY, uiContainer,
									&uiDrn, pRecord, uiAutoTrans);
		goto ExitCS;
	}

	if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
			FDB_TRANS_GOING_OK, uiAutoTrans, &bStartedAutoTrans)))
	{
		goto Exit;
	}

	if( pDb->uiFlags & FDB_COMMITTING_TRANS)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_TRANS_OP);
		goto Exit;
	}

	if ((pDbStats = pDb->pDbStats) != NULL)
	{
		f_timeGetTimeStamp( &StartTime);
	}

	// Make sure we have a valid record

	if( !pRecord)
	{
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}

	// We cannot modify a record that is marked read-only.

	if( pRecord->isReadOnly())
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if( !uiDrn || (uiDrn == (FLMUINT) DRN_LAST_MARKER))
	{
		rc = RC_SET( FERR_BAD_DRN);
		goto Exit;
	}

	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}

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

	// DICTIONARY RECORD MODIFY

	if( uiContainer == FLM_LOCAL_DICT_CONTAINER) 
	{
		if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
			uiContainer, uiDrn, FALSE, NULL, NULL, &pOldRecord)))
		{

			// NOTE: Deliberately not reading in to cache if not found.

			if (rc != FERR_NOT_FOUND)
			{
				goto Exit;
			}
			if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, &pOldRecord, NULL, NULL)))
			{
				goto Exit;
			}
		}

		// Sanity check -- make sure that the new and old records point at
		// different objects.

		flmAssert( pRecord != pOldRecord);

		if( RC_BAD( rc = flmLFileDictUpdate( pDb, &pLFile, &uiDrn, 
				pRecord, pOldRecord,
				(uiAutoTrans & FLM_DO_IN_BACKGROUND) ? TRUE : FALSE, 
				(uiAutoTrans & FLM_SUSPENDED) ? TRUE : FALSE,
				&bLogCompleteIndexSet)))
		{
			goto Exit;
		}

		pRecord->setID( uiDrn);
		pRecord->setContainerID( uiContainer);
		if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord)))
		{
			goto Exit;
		}

		goto Exit;
	}

	// First read the old record, and delete it's keys.
	// To do this we need to be able to read any purged fields and delete any
	// keys they build.

	if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
		uiContainer, uiDrn, FALSE, NULL, NULL, &pOldRecord)))
	{

		// NOTE: Deliberately not reading in to cache if not found.

		if (rc != FERR_NOT_FOUND)
		{
			goto Exit;
		}
		
		if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, &pOldRecord, NULL, NULL)))
		{
			goto Exit;
		}
	}

	// Sanity check -- make sure that the new and old records point at
	// different objects.

	flmAssert( pRecord != pOldRecord);

	bProcessedKeys = TRUE;
	bHadUniqueKeys = FALSE;
	if( RC_BAD( rc = flmProcessRecFlds( pDb, NULL, uiContainer, uiDrn, pOldRecord,
													KREF_DEL_KEYS | KREF_IN_MODIFY,
													TRUE,		// Purged Field OK
													&bHadUniqueKeys)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = flmProcessRecFlds( pDb, NULL, uiContainer, uiDrn, pRecord,
													KREF_ADD_KEYS | KREF_IN_MODIFY,
													FALSE,
													&bHadUniqueKeys)))
	{
		goto Exit;
	}
	
	// NOTE: The LFile table may have changed locations if the dictionary 
	// was update because of a change in a field state
	
	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}
	
	if( RC_BAD( rc = FSRecUpdate( pDb, pLFile, pRecord, uiDrn, REC_UPD_MODIFY)))
	{
		 goto Exit;
	}

	// Finish up the keys adding the unique keys to the indexes.

	if( RC_BAD( rc = KYProcessDupKeys( pDb, bHadUniqueKeys)))
	{
		// Undo the record that was modified - replace with original record.
		if( RC_BAD( rc1 = FSRecUpdate( pDb, pLFile, 
			pOldRecord, uiDrn, REC_UPD_MODIFY)))
		{
			rc = (rc == FERR_NOT_UNIQUE) ? rc1 : rc;
		}
		goto Exit;
	}

	// Insert record into cache
	
	pRecord->setID( uiDrn);
	pRecord->setContainerID( uiContainer);
	
	if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord)))
	{
		if ( rc != FERR_MEM)
		{
			flmAssert( 0);
		}
		
		// Undo the record that was modified - replace with original record.
		
		FSRecUpdate( pDb, pLFile, pOldRecord, uiDrn, REC_UPD_MODIFY);
		goto Exit;
	}

	// Don't make this call until we are sure of success - because we want to
	// be able to back things out of KREF table.

	KYFinishCurrentRecord( pDb);

Exit:

	if( RC_BAD( rc) && bProcessedKeys)
	{
		KYAbortCurrentRecord( pDb);
	}

	// Add the BLOB entries to the blob list.
	
	rc = FB_OperationEnd( pDb, rc);

	if( RC_OK( rc))
	{
		if( RC_OK( rc = pDb->pFile->pRfl->logUpdate( 
				uiContainer, uiDrn, uiAutoTrans, pOldRecord, pRecord)) && 
			 bLogCompleteIndexSet &&
			 pDb->pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51)
		{
			// Log the fact that we indexed everything so the redo will also
			// index all data records in the container.

			rc = pDb->pFile->pRfl->logIndexSet( uiDrn, 0, 1, 0xFFFFFFFF);
		}
	}

	if( pDbStats)
	{
		flmAddElapTime( &StartTime, &pDbStats->RecordModifies.ui64ElapMilli);
		pDbStats->RecordModifies.ui64Count++;
		pDbStats->bHaveStats = TRUE;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_MODIFY_RECORD, hDb, rc, uiDrn,
								uiContainer, pRecord, pOldRecord);
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, 
		pDb->LogHdr.uiCurrTransID, uiContainer, uiDrn, rc, "RMod");
#endif

	// If started an automatic transaction, end it.

	if( bStartedAutoTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}

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

ExitCS:

	flmExit( FLM_RECORD_MODIFY, pDb, rc);
	return( rc);
}
Пример #9
0
RCODE CSPDB::AddIndex(HFDB hFlaim, FLMUNICODE *pFieldName, FLMUINT fieldId)
{
	RCODE			rc = FERR_OK;
	FlmRecord		*pRec = NULL;
	void			*pvIndex;
	void			*pvField = 0;
	void			*pvKey = 0;
	FLMUNICODE*		pIndexName;
	int				nameLen;
	int				buffLen;
	FLMUINT			indexId = 0;
	
 	pRec = new FlmRecord();
 	if (pRec != NULL)
 	{
 		// Add the index.
 		rc = pRec->insertLast(0, FLM_INDEX_TAG, FLM_TEXT_TYPE, &pvIndex);
 		if (RC_OK(rc))
 		{
			// Create the index name.
			nameLen = f_unilen(pFieldName);
			buffLen = nameLen + sizeof(nameSuffex) + 1;
			pIndexName = new FLMUNICODE[buffLen];
			if (pIndexName)
			{
				f_unicpy(pIndexName, pFieldName);
				f_unicpy(pIndexName + nameLen, (FLMUNICODE*)nameSuffex);
				rc = pRec->setUnicode(pvIndex, (FLMUNICODE*)pIndexName);
				if (RC_OK(rc))
				{
					// Add the key.
					rc = pRec->insert(pvIndex, INSERT_LAST_CHILD, FLM_KEY_TAG, FLM_TEXT_TYPE, &pvKey);
					if (RC_OK(rc))
					{
						// Add the collection
						rc = pRec->insert(pvKey, INSERT_LAST_CHILD, FLM_FIELD_TAG, FLM_NUMBER_TYPE, &pvField);
						if (RC_OK(rc))
						{
							rc = pRec->setINT(pvField, CS_Id_CollectionId);
						}
						// Add the field.
						rc = pRec->insert(pvKey, INSERT_FIRST_CHILD, FLM_FIELD_TAG, FLM_NUMBER_TYPE, &pvField);
						if (RC_OK(rc))
						{
							rc = pRec->setINT(pvField, fieldId);
							if (RC_OK(rc))
							{
								rc = FlmRecordAdd(hFlaim, FLM_DICT_CONTAINER, &indexId, pRec, 0);
								if (RC_OK(rc))
								{
									rc = m_NameTable.addTag((FLMUNICODE*)pIndexName, 0, indexId, 0, 0, TRUE);
								}
							}
						}
						else
						{
							rc = FERR_BAD_FIELD_TYPE;
						}
					}
				}
				delete [] pIndexName;
			}
 		}
 	  	pRec->Release();
 	}
 	else
 	{
 		rc = FERR_MEM;
 	}

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

	if (!gv_bViewHdrRead)
		ViewReadHdr();

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

	ViewGetDictInfo();
	if (gv_bViewHaveDictInfo)
	{

		/* Find the logical file */

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

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

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

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

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

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

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

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

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

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

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

		/* Collate the name. */

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

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

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

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

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

		i = 0;
		while (i < NumFields)
		{

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

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

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

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

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

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

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

		/* Convert the key to binary format */

		if (!KeyEntered)
			goto Exit_False;

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

Exit_False:
	GetOK = FALSE;
Exit_GetKey:
	if (pKey)
	{
		pKey->Release();
	}
	return( GetOK);
}
Пример #11
0
/********************************************************************
Desc: Loads the database with objects.
*********************************************************************/
RCODE gigaLoadDatabase( void)
{
	RCODE				rc = NE_FLM_OK;
	FLMBOOL			bTransActive = FALSE;
	FLMBOOL			bCommitTrans = FALSE;
	FLMUINT			uiObjsInTrans = 0;
	FLMUINT			uiChar = 0;
	FLMUINT			bSuspend = FALSE;
	FlmRecord *		pNewRec = NULL;

	// Set cache size, if specified on command line.

	if( gv_uiCacheSize)
	{
		if( RC_BAD( rc = FlmSetHardMemoryLimit( 0, FALSE, 0,
			gv_uiCacheSize, 0)))
		{
			gigaOutputRcErr( "setting cache size", rc);
			goto Exit;
		}
	}

	// Set block cache percentage, if it is not default.
	
	if( gv_uiBlockCachePercentage != 50)
	{
		if( RC_BAD( rc = FlmConfig( FLM_BLOCK_CACHE_PERCENTAGE,
			(void *)gv_uiBlockCachePercentage, (void *)0)))
		{
			gigaOutputRcErr( "setting block cache percentage", rc);
			goto Exit;
		}
	}

	// Set the maximum and low dirty cache, if one was specified

	if( gv_uiMaxDirtyCache)
	{
		if( RC_BAD( rc = FlmConfig( FLM_MAX_DIRTY_CACHE,
			(void *)gv_uiMaxDirtyCache, (void *)gv_uiLowDirtyCache)))
		{
			gigaOutputRcErr( "setting maximum dirty cache", rc);
			goto Exit;
		}
	}

	// Set checkpoint interval, if one is specified.

	if( gv_uiCPInterval != 0xFFFFFFFF)
	{
		if( RC_BAD( rc = FlmConfig( FLM_MAX_CP_INTERVAL, 
			(void *)gv_uiCPInterval, (void *)0)))
		{
			gigaOutputRcErr( "setting checkpoint interval", rc);
			goto Exit;
		}
	}
	
	// Enable/Disable direct I/O
	
	if( RC_BAD( rc = FlmConfig( FLM_DIRECT_IO_STATE, 
		(void *)!gv_bDisableDirectIO, NULL)))
	{
		goto Exit;
	}

	// Create the database.
	
	(void)FlmDbRemove( gv_szDibName, gv_szDataDir, gv_szRflDir, TRUE);
	
	if( RC_BAD( rc = FlmDbCreate( gv_szDibName, gv_szDataDir, gv_szRflDir, 
		NULL, gv_pszGigaDictionary, NULL, &gv_hDb)))
	{
		gigaOutputRcErr( "creating database", rc);
		goto Exit;
	}
	
	if( RC_BAD( rc = FlmDbConfig( gv_hDb, 
		FDB_RFL_FOOTPRINT_SIZE, (void *)(512 * 1024 * 1024), NULL)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = FlmDbConfig( gv_hDb, 
		FDB_RBL_FOOTPRINT_SIZE, (void *)(512 * 1024 * 1024), NULL)))
	{
		goto Exit;
	}

	// Create the display

	gv_uiTotalLoaded = 0;
	gv_ui10SecTotal = 0;
	
	f_mutexLock( gv_hWindowMutex);
	FTXWinClear( gv_pWindow);
	f_mutexUnlock( gv_hWindowMutex);

	gigaOutputLabel( MAX_CACHE_ROW, "Maximum Cache Size (bytes)");
	gigaOutputLabel( USED_CACHE_ROW, "Cache Used (bytes)");
	gigaOutputLabel( ITEMS_CACHED_ROW, "Cache Used (items)");
	gigaOutputLabel( DIRTY_CACHE_ROW, "Dirty Cache (bytes)");
	gigaOutputLabel( LOG_CACHE_ROW, "Log Cache (bytes)");
	gigaOutputLabel( FREE_CACHE_ROW, "Free Cache (bytes)");
	gigaOutputLabel( CP_STATE_ROW, "Checkpoint State");
	
	gigaUpdateMemInfo();

	gigaOutputLabel( DB_NAME_ROW, "Database Name");
	gigaOutputStr( DB_NAME_ROW, gv_szDibName);

	gigaOutputLabel( TOTAL_TO_LOAD_ROW, "Total To Load");
	gigaOutputUINT( TOTAL_TO_LOAD_ROW, gv_uiTotalToLoad);

	gigaOutputLabel( TRANS_SIZE_ROW, "Transaction Size");
	gigaOutputUINT( TRANS_SIZE_ROW, gv_uiTransSize);

	gigaOutputLabel( TOTAL_LOADED_ROW, "Total Loaded");
	gigaOutputUINT( TOTAL_LOADED_ROW, gv_uiTotalLoaded);

	gigaOutputLabel( ADDS_PER_SEC_CURRENT, "Adds/Sec. (10 secs)");
	gigaOutputUINT( ADDS_PER_SEC_CURRENT, 0);

	gigaOutputLabel( ADDS_PER_SEC_OVERALL, "Adds/Sec. (overall)");
	gigaOutputUINT( ADDS_PER_SEC_OVERALL, 0);

	gigaOutputLabel( ELAPSED_TIME_ROW, "Elapsed Time");
	gigaOutputStr( ELAPSED_TIME_ROW, "<none>");

	if( RC_BAD( rc = gigaStartScreenThread()))
	{
		goto Exit;
	}
	
	gv_ui10SecStartTime = gv_uiStartTime = FLM_GET_TIMER();
	gv_ui10Secs = FLM_SECS_TO_TIMER_UNITS( 10);
	gv_ui1Sec = FLM_SECS_TO_TIMER_UNITS( 1);
	
	for( ;;)
	{
		// See if we have been told to shut down, or if the user 
		// has pressed escape.

		if( gv_bShutdown)
		{
			break;
		}

		// Every 127 objects, see if character was pressed and update 
		// count on screen.

		if( (gv_uiTotalLoaded & 0x7F) == 0)
		{
			f_yieldCPU();
			
			if( (uiChar = gigaSeeIfQuit()) != 0)
			{
				if( uiChar == FKB_ESCAPE)
				{
					break;
				}
				else if( uiChar == 's' || uiChar == 'S')
				{
					bSuspend = TRUE;
				}
			}

			// Check for other keyboard options
		}
		else if( (gv_uiTotalLoaded & 0x7) == 0)
		{
			FLMUINT		uiElapsedTime;
			FLMUINT		uiCurrTime;

			uiCurrTime = FLM_GET_TIMER();

			// If at least 10 seconds have elapsed, redisplay the average
			// rate values.

			if( (uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime,
				gv_ui10SecStartTime)) >= gv_ui10Secs)
			{
				gigaUpdateLoadTimes();
			}
		}

		// Start a transaction, if one is not going.

		if( !bTransActive)
		{
			if( bSuspend)
			{
				uiChar = gigaGetInput(
					"Load suspended, press any character to continue loading: ",
					NULL);
				bSuspend = FALSE;
			}
			
			if( RC_BAD( rc = gigaStartTrans()))
			{
				goto Exit;
			}
			
			bTransActive = TRUE;
			bCommitTrans = FALSE;
			uiObjsInTrans = 0;
		}

		// Increment the load counters and determine if this will be the
		// last object of the transaction.

		gv_uiTotalLoaded++;
		uiObjsInTrans++;
		
		if( uiObjsInTrans == gv_uiTransSize ||
			 gv_uiTotalLoaded == gv_uiTotalToLoad)
		{
			bCommitTrans = TRUE;
		}

		// Create a new object.

		if( RC_BAD( rc = gigaMakeNewRecord( &pNewRec)))
		{
			goto Exit;
		}
		
		if( RC_BAD( rc = FlmRecordAdd( gv_hDb, FLM_DATA_CONTAINER, 
			NULL, pNewRec, FLM_DONT_INSERT_IN_CACHE)))
		{
			goto Exit;
		}
		
		// Commit when we reach the transaction size or the total to load.
		// NOTE: The bCommitTrans flag is set above.

		if( bCommitTrans)
		{
			if( RC_BAD( rc = gigaCommitTrans()))
			{
				goto Exit;
			}
			
			bTransActive = FALSE;
		}

		// See if we are done.

		if( gv_uiTotalLoaded == gv_uiTotalToLoad)
		{
			flmAssert( !bTransActive);
			break;
		}
	}

Exit:

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

	if( bTransActive)
	{
		(void)FlmDbTransAbort( gv_hDb);
	}
	
	if( gv_hDb != HFDB_NULL)
	{
		FlmDbCheckpoint( gv_hDb, FLM_NO_TIMEOUT);
		gigaStopScreenThread();
		FlmDbClose( &gv_hDb);

		// This will cause us to wait for the last checkpoint
		// to finish.

		(void)FlmConfig( FLM_CLOSE_FILE, (void *)gv_szDibName,
								(void *)gv_szDataDir);
	}
	
	gigaUpdateLoadTimes();
	gigaStopScreenThread();
	f_threadDestroy( &gv_pIxManagerThrd);
	
	return( rc);
}
Пример #12
0
/********************************************************************
Desc:
*********************************************************************/
RCODE gigaMakeNewRecord(
	FlmRecord **		ppRecord)
{
	RCODE					rc = NE_FLM_OK;
	FlmRecord *			pRecord = NULL;
	void *				pvField;

	if( *ppRecord && !(*ppRecord)->isReadOnly())
	{
		f_assert( (*ppRecord)->getRefCount() == 1);
		pRecord = *ppRecord;
		*ppRecord = NULL;
		pRecord->clear();
	}
	else
	{
		if( (pRecord = f_new FlmRecord) == NULL)
		{
			rc = RC_SET( NE_FLM_MEM);
			goto Exit;
		}
	}

	if( RC_BAD( rc = pRecord->insertLast( 0, PERSON_TAG,
		FLM_TEXT_TYPE, NULL)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = pRecord->insertLast( 1, FIRST_NAME_TAG,
		FLM_TEXT_TYPE, &pvField)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = pRecord->setNative( pvField, *gv_ppszCurrGiven)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = pRecord->insertLast( 1, LAST_NAME_TAG,
		FLM_TEXT_TYPE, &pvField)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = pRecord->setNative( pvField, *gv_ppszCurrFamily)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = pRecord->insertLast( 1, AGE_TAG,
		FLM_NUMBER_TYPE, &pvField)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = pRecord->setUINT( pvField, f_getRandomUINT32( 1, 100))))
	{
		goto Exit;
	}

	if( *ppRecord)
	{
		(*ppRecord)->Release();
	}
	
	*ppRecord = pRecord;
	pRecord = NULL;
	
	gv_ppszCurrGiven++;
	if( *gv_ppszCurrGiven == NULL)
	{
		gv_ppszCurrGiven = &gv_pszGivenNames [0];
		gv_ppszCurrFamily++;
		
		if (*gv_ppszCurrFamily == NULL)
		{
			gv_ppszCurrFamily = &gv_pszFamilyNames[0];
		}
	}
	
Exit:

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

	return( rc);
}