Exemplo n.º 1
0
/****************************************************************************
Desc:		Internal interface routine for database add operation.
			Must be in a valid transaction.
Note:		Internal name is used so that later we can call this within FLAIM.
****************************************************************************/
RCODE	flmAddRecord(
	FDB *	 		pDb,
	LFILE *		pLFile,
	FLMUINT *	puiDrn,						// Record Number to set AND return.
	FlmRecord * pRecord,						// Record to add, must NOT be NULL.
	FLMBOOL		bBatchProcessing,			// Set to TRUE if called by REBUILD.
	FLMBOOL		bDoInBackground,
	FLMBOOL		bCreateSuspended,
	FLMBOOL		bKeepInCache,
	FLMBOOL *	pbLogCompleteIndexSet)
{
	RCODE			rc = FERR_OK;
	FLMUINT		uiDrn = 0;
	FLMBOOL		bProcessedKeys = FALSE;
	FLMUINT		uiLfNum = pLFile->uiLfNum;
	FLMUINT		uiAddAppendFlags = REC_UPD_ADD;
	FLMBOOL		bHadUniqueKeys;

	if( puiDrn)
	{
		uiDrn = *puiDrn;
	}

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

	// Assert that the record is not read-only

	flmAssert( !pRecord->isReadOnly());

	// Set up for indexing.

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

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

	// If this is a dictionary record then one routine takes care of it.

	if( pLFile->uiLfNum == FLM_LOCAL_DICT_CONTAINER)
	{
		if( RC_OK( rc = flmLFileDictUpdate( pDb, &pLFile, &uiDrn,
					pRecord, NULL, bDoInBackground, bCreateSuspended,
					pbLogCompleteIndexSet)))
		{
			if( puiDrn)
			{
				*puiDrn = uiDrn;
			}
		}

		goto Exit;
	}
	else
	{
		if( !uiDrn || uiDrn == DRN_LAST_MARKER)
		{
			if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE, &uiDrn)))
			{
#ifdef FLM_DBG_LOG
				uiDrn = 0;
#endif
				goto Exit;
			}
			
			uiAddAppendFlags |= REC_UPD_NEW_RECORD;
		}
	}

	// Add the records keys, and then the record.  NOTE: If the bBatchProcessing
	// flag is set to TRUE, we are being called as part of a rebuild.  In this
	// case, we do NOT want BLOBs to be reprocessed.  Also, we do not want
	// the QF job list to be generated (it could get very large - and all of
	// the entries are stored in a single record).  So we set the
	// KREF_INDEXING_ONLY flag.  This flag will prohibit the processing of
	// BLOB data.  Also, it will prohibit constructing a QF job list.  Instead
	// of the QF job list, the entries will be fed directly to QuickFinder and
	// then processed when KYKeysCommit is called.

	bProcessedKeys = TRUE;
	bHadUniqueKeys = FALSE;
	if( RC_BAD( rc = flmProcessRecFlds( pDb, NULL, pLFile->uiLfNum, uiDrn, pRecord,
										(FLMUINT)((bBatchProcessing)
											? (KREF_ADD_KEYS | KREF_INDEXING_ONLY)
											: KREF_ADD_KEYS),
											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, uiLfNum, &pLFile)))
	{
		goto Exit;
	}

	if( RC_BAD(	rc = FSRecUpdate( pDb, pLFile, pRecord,
											uiDrn, uiAddAppendFlags)))
	{
		goto Exit;
	}

	if( puiDrn)
	{
		*puiDrn = uiDrn;
	}

	// Sort and check keys for uniqueness.
	
	if( RC_BAD( rc = KYProcessDupKeys( pDb, bHadUniqueKeys)))
	{
		// Remove the record that was added because of the error.

		RCODE		rc1 = FSRecUpdate( pDb, pLFile, NULL, uiDrn, REC_UPD_DELETE);
		if( RC_BAD(rc1))
		{
			rc = (rc == FERR_NOT_UNIQUE) ? rc1 : rc;
		}
		goto Exit;
	}

	// Insert record into cache

	pRecord->setID( uiDrn);
	pRecord->setContainerID( pLFile->uiLfNum);
	if (bKeepInCache)
	{
		if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord)))
		{
			// Remove the record that was added because of the error.

			FSRecUpdate( pDb, pLFile, NULL, uiDrn, REC_UPD_DELETE);
			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);
	}
	
#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, 
		uiLfNum, uiDrn, rc, "RAdd");
#endif

	return( rc);
}
Exemplo n.º 2
0
/****************************************************************************
Desc : Suspend the selected index from doing any key updates on records
		 that are equal or higher than the next record ID value
		 in the container that the index references.  If the index is offline
		 then the background process will be suspended.  If the index is
		 online then it will be suspended.  If the index is already 
		 suspended FERR_OK will be returned.  A suspended index is not
		 persistant if the database goes down.  
Notes: An update transaction will be started if necessary.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmIndexSuspend(
	HFDB			hDb,
	FLMUINT		uiIndexNum)
{
	RCODE			rc = FERR_OK;
	FDB *			pDb = (FDB *)hDb;
	IXD *			pIxd;
	FLMUINT		uiHighestRecId;
	FLMUINT		uiContainerNum;
	FLMBOOL		bSuspended;
	FLMBOOL		bStartedTrans = FALSE;
	LFILE *		pLFile;

	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_INDEX, FCS_OP_INDEX_SUSPEND)))
		{
			goto Exit;
		}

		if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_INDEX_ID, uiIndexNum)))
		{
			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;
	}

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

	// See if the index is valid

	if( RC_BAD( rc = fdictGetIndex(
		pDb->pDict,
		pDb->pFile->bInLimitedMode,
		uiIndexNum, NULL, &pIxd, TRUE)))
	{
		goto Exit;
	}

	if( pIxd->uiFlags & IXD_UNIQUE)
	{
		// Can't suspend unique indexes
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if( pIxd->uiFlags & IXD_SUSPENDED)
	{
		// Index is already suspended.
		goto Exit;
	}

	// Get the current index info from the tracker

	if( RC_BAD( rc = flmGetIxTrackerInfo( pDb,
		uiIndexNum, &uiContainerNum, &uiHighestRecId, NULL, &bSuspended)))
	{
		goto Exit;
	}
	flmAssert( !bSuspended);

	// Get information about the container(s) being indexed

	if( !(pIxd->uiFlags & IXD_OFFLINE))
	{
		if ((uiContainerNum = pIxd->uiContainerNum) == 0)
		{
			// The index was on-line and up-to-date.  For an index that
			// crosses all containers, we will suspend on the highest DRN of
			// the FLM_DATA_CONTAINER.

			uiContainerNum = FLM_DATA_CONTAINER;
		}

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

		uiHighestRecId = 0;
		if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE, &uiHighestRecId)))
		{
			goto Exit;
		}

		// Decrement uiHighestRecId by 1 to correctly reflect the
		// last record that was indexed.

		flmAssert( uiHighestRecId != 0);
		uiHighestRecId--;
	}

	// There may be a background thread still assigned to the
	// index even though the index may be "on-line."  This is because
	// the background thread may have just commited a transaction that
	// transitioned the index from off-line to on-line, but the thread
	// has not yet exited (even though it will not do any more work
	// to update the index).  We want to wait for the thread to terminate
	// before our transaction is allowed to commit.  This is so that if
	// we immediately call resume, it won't find the yet-to-terminate
	// thread still running in the background.

	if( !(pDb->uiFlags & FDB_REPLAYING_RFL))
	{
		if( RC_BAD( rc = flmAddToStopList( pDb, uiIndexNum)))
		{
			goto Exit;
		}
	}

	flmAssert( uiContainerNum != 0xFFFFFFFF);

	if( RC_BAD( rc = flmSetIxTrackerInfo( pDb, 
		uiIndexNum, uiContainerNum, uiHighestRecId, 
		TRANS_ID_OFFLINE, TRUE)))
	{
		goto Exit;
	}

	// Create a new dictionary

	if( !(pDb->uiFlags & FDB_UPDATED_DICTIONARY))
	{
		if( RC_BAD( rc = fdictCloneDict( pDb)))
		{
			goto Exit;
		}

		// Get a pointer to the new IXD

		if( RC_BAD( rc = fdictGetIndex( pDb->pDict,
			pDb->pFile->bInLimitedMode,
			uiIndexNum, NULL, &pIxd, TRUE)))
		{
			goto Exit;
		}
	}

	// Update the IXDs flags so that the current update
	// transaction will see the correct state of the index.
	// Old read transactions will continue to use a prior
	// version of the dictionary.

	pIxd->uiFlags |= (IXD_SUSPENDED | IXD_OFFLINE);

	// Log the suspend packet to the RFL

	if( RC_BAD( rc = pDb->pFile->pRfl->logIndexSuspendOrResume( 
		uiIndexNum, RFL_INDEX_SUSPEND_PACKET)))
	{
		goto Exit;
	}

Exit:

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

	flmExit( FLM_INDEX_SUSPEND, pDb, rc);
	return( rc);
}
Exemplo n.º 3
0
/****************************************************************************
Desc:		Returns the next DRN that record ADD would return.  The database
			must be in an existing update transaction.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmReserveNextDrn(
	HFDB			hDb,
	FLMUINT		uiContainer,
	FLMUINT *	puiDrnRV)
{
	RCODE			rc;
	FDB *			pDb = (FDB *)hDb;
	LFILE *		pLFile;
	FLMBOOL		bIgnore;
	FLMUINT		uiDrn = 0;

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

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

		// Send the request

		if( RC_BAD( rc = Wire.sendOp( 
			FCS_OPCLASS_RECORD, FCS_OP_RESERVE_NEXT_DRN)))
		{
			goto ExitCS;
		}

		if( uiContainer)
		{
			if (RC_BAD( rc = Wire.sendNumber(
				WIRE_VALUE_CONTAINER_ID, uiContainer)))
			{
				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 ExitCS;
		}

		*puiDrnRV = Wire.getDrn();
		goto ExitCS;

Transmission_Error:
		pCSContext->bConnectionGood = FALSE;
		goto ExitCS;
	}

	bIgnore = FALSE;					// Set to shut up compiler.

	if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
										FDB_TRANS_GOING_OK,	// byFlags
										0, 						// wAutoTrans
										&bIgnore)))				// bStartedAutoTrans
	{
		goto Exit;
	}

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

	if( RC_BAD( fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
#ifdef FLM_DBG_LOG
		uiDrn = 0;
#endif
		goto Exit;
	}
	uiDrn = (FLMUINT) 0;					// Must initialize before call.
	if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, TRUE, &uiDrn)))
	{
#ifdef FLM_DBG_LOG
		uiDrn = 0;
#endif
		goto Exit;
	}

	*puiDrnRV = uiDrn;						// Set return value.

Exit:

	if (RC_OK( rc))
	{
		rc = pDb->pFile->pRfl->logUpdatePacket( 
			RFL_RESERVE_DRN_PACKET, uiContainer, *puiDrnRV, 0);
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_RESERVE_DRN, hDb, rc, *puiDrnRV,
								uiContainer, NULL, NULL);
	}

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

ExitCS:

	flmExit( FLM_RESERVE_NEXT_DRN, pDb, rc);

	return( rc);
}