Files
mars-flaim/flaim/src/flrddrct.cpp
ahodgkinson f54e6ce080 Changed license to LGPL.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2007-01-23 09:38:48 +00:00

444 lines
8.9 KiB
C++

//-------------------------------------------------------------------------
// Desc: Retrieve record from database.
// Tabs: 3
//
// Copyright (c) 1990, 1994-2007 Novell, Inc. All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version 2.1
// of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com.
//
// $Id$
//------------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC RCODE flmRecordRetrieveCS(
FDB * pDb,
FLMUINT uiContainer,
FLMUINT uiDrn,
FLMUINT uiFlag,
FlmRecord ** ppRecord,
FLMUINT * puiDrnRV);
/****************************************************************************
Desc: Retrieves a single record from a container.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmRecordRetrieve(
HFDB hDb,
FLMUINT uiContainer,
FLMUINT uiDrn,
FLMUINT uiFlag,
FlmRecord ** ppRecord,
FLMUINT * puiDrnRV)
{
FLMUINT uiKeyRelPos;
FLMBOOL bTransStarted;
FLMUINT uiFoundDrn;
LFILE * pLFile;
BTSK stack[ BH_MAX_LEVELS];
FLMBOOL bStackInitialized = FALSE;
BTSK * pStack;
FLMBYTE pSearchBuf[ DRN_KEY_SIZ + 4];
FLMBYTE pKeyBuf[ DRN_KEY_SIZ + 4];
FDB * pDb = (FDB *)hDb;
FLMUINT uiSaveInitNestLevel = 0;
DB_STATS * pDbStats;
RCODE rc = FERR_OK;
#ifdef FLM_DEBUG
flmAssert( hDb != NULL);
flmAssert( uiContainer != 0);
#endif
bTransStarted = FALSE;
uiFoundDrn = 0;
if( !uiDrn && (uiFlag & (FO_EXACT | FO_INCL)))
{
if( uiFlag & FO_INCL)
{
uiDrn = 1;
}
else
{
rc = RC_SET( FERR_NOT_FOUND);
goto Exit;
}
}
if (IsInCSMode( hDb))
{
fdbInitCS( pDb);
rc = flmRecordRetrieveCS( pDb, uiContainer, uiDrn, uiFlag,
ppRecord, puiDrnRV);
goto ExitCS;
}
// Remove the exclusive case and turn it into an inclusive search.
if( uiFlag & FO_EXCL)
{
// For records, exclusive is same as inclusive drn+1
uiDrn++;
uiFlag &= ~FO_EXCL;
uiFlag = FO_INCL;
}
uiSaveInitNestLevel = pDb->uiInitNestLevel;
// Test both FO_FIRST and FO_LAST at the same time to save time.
if (uiFlag & (FO_FIRST | FO_LAST))
{
if (uiFlag & FO_FIRST)
{
uiFlag = FO_INCL;
uiDrn = 1;
}
else
{
uiFlag = FO_LAST;
uiDrn = DRN_LAST_MARKER - 1;
goto Search_Record;
}
}
if( uiFlag & FO_EXACT)
{
if( RC_OK( rc = flmRcaRetrieveRec( pDb, &bTransStarted,
uiContainer, uiDrn, TRUE, NULL, NULL, ppRecord)))
{
uiFoundDrn = uiDrn;
}
else if (rc != FERR_NOT_FOUND || ppRecord)
{
goto Exit;
}
// else do nothing - fall through, because even though we passed
// TRUE in for the bOkToGetFromDisk parameter, flmRcaRetrieveRec
// will NOT try to fetch from disk if ppRecord is NULL - so
// we still need to try to fetch from disk.
}
else // only FO_INCL case can exist for the else case.
{
// Let's be optimistic and see if record is already in cache
// before we search the b-tree. Don't try to retrieve the record from
// disk if it is not in cache ... the next record may not have a DRN
// of uiDrn and we don't want to search the b-tree twice to fetch
// the next record.
if( RC_OK( rc = flmRcaRetrieveRec( pDb, &bTransStarted,
uiContainer, uiDrn, FALSE, NULL, NULL, ppRecord)))
{
uiFoundDrn = uiDrn;
}
else if( rc != FERR_NOT_FOUND)
{
goto Exit;
}
// else - rc == FERR_NOT_FOUND, so we need to see if we can find the
// next record on disk.
}
if( !uiFoundDrn)
{
Search_Record:
if( uiSaveInitNestLevel == pDb->uiInitNestLevel)
{
if ( RC_BAD( rc = fdbInit( pDb, FLM_READ_TRANS,
FDB_TRANS_GOING_OK, 0, &bTransStarted)))
{
goto Exit;
}
}
if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
{
goto Exit;
}
f_UINT32ToBigEndian( (FLMUINT32)uiDrn, pSearchBuf);
FSInitStackCache( &stack [0], BH_MAX_LEVELS);
pStack = &stack[0];
bStackInitialized = TRUE;
pStack->pKeyBuf = pKeyBuf;
// Search the B-Tree for the key.
if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, pSearchBuf, 4, 0)))
{
goto Exit;
}
uiKeyRelPos = pStack->uiCmpStatus;
if( uiFlag & FO_EXACT)
{
if( uiKeyRelPos != BT_EQ_KEY)
{
rc = RC_SET( FERR_NOT_FOUND);
goto Exit;
}
}
else // inclusive or FO_LAST
{
// Handle FO_LAST case - If FO_LAST bit was set, uiFlag will
// have been changed above to simply be equal to FO_LAST.
if (uiFlag == FO_LAST)
{
if (pStack->uiBlkAddr == BT_END)
{
rc = RC_SET( FERR_BOF_HIT);
goto Exit;
}
if (uiKeyRelPos == BT_END_OF_DATA ||
f_bigEndianToUINT32( pKeyBuf) > uiDrn)
{
// Position to the last element in the block.
if (RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack)))
{
if (rc == FERR_BT_END_OF_DATA)
{
rc = RC_SET( FERR_BOF_HIT);
}
goto Exit;
}
// Position to beginning of record.
while (BBE_NOT_FIRST( CURRENT_ELM( pStack )))
{
if (RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack)))
{
if (rc == FERR_BT_END_OF_DATA)
{
rc = RC_SET( FERR_BTREE_ERROR);
}
goto Exit;
}
}
}
}
else if( uiKeyRelPos == BT_END_OF_DATA)
{
rc = RC_SET( FERR_EOF_HIT);
goto Exit;
}
}
uiFoundDrn = f_bigEndianToUINT32( pKeyBuf);
if( uiFoundDrn == DRN_LAST_MARKER)
{
if( uiFlag & FO_EXACT)
{
rc = RC_SET( FERR_NOT_FOUND);
}
else
{
rc = RC_SET( FERR_EOF_HIT);
}
goto Exit;
}
// Need to return the record?
if( ppRecord)
{
if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
uiContainer, uiFoundDrn, TRUE, pStack, pLFile, ppRecord)))
{
goto Exit;
}
}
}
if( puiDrnRV)
{
*puiDrnRV = uiFoundDrn;
}
if( (pDbStats = pDb->pDbStats) != NULL)
{
pDbStats->bHaveStats = TRUE;
pDbStats->ui64NumRecordReads++;
}
ExitCS:
// Call record validator callback
if( pDb->fnRecValidator)
{
FLMBOOL bSavedInvisTrans;
CB_ENTER( pDb, &bSavedInvisTrans);
(void)(pDb->fnRecValidator)( FLM_RECORD_RETRIEVE, hDb,
uiContainer, *ppRecord, NULL, pDb->RecValData, &rc);
CB_EXIT( pDb, bSavedInvisTrans);
}
Exit:
if (bStackInitialized)
{
FSReleaseStackCache( stack, BH_MAX_LEVELS, FALSE);
}
if (bTransStarted)
{
RCODE rc2 = flmAbortDbTrans( pDb);
if (RC_OK( rc))
{
rc = rc2;
}
}
// Don't want it to call fdbExit if fdbInit wasn't called.
if (pDb->uiInitNestLevel == uiSaveInitNestLevel)
{
pDb = NULL;
}
flmExit( FLM_RECORD_RETRIEVE, pDb, rc);
return( rc);
}
/****************************************************************************
Desc: Retrieves a record based on uiDrn and uiFlag client-server.
****************************************************************************/
FSTATIC RCODE flmRecordRetrieveCS(
FDB * pDb,
FLMUINT uiContainer,
FLMUINT uiDrn,
FLMUINT uiFlag,
FlmRecord ** ppRecord,
FLMUINT * puiDrnRV)
{
RCODE rc;
CS_CONTEXT * pCSContext = pDb->pCSContext;
void * pvMark = pCSContext->pool.poolMark();
FCL_WIRE Wire( pCSContext, pDb);
// Set the record object so that it can be re-used,
// if possible
if( ppRecord)
{
Wire.setRecord( *ppRecord);
if( *ppRecord)
{
(*ppRecord)->Release();
*ppRecord = NULL;
}
}
// Set the temporary pool
Wire.setPool( &pCSContext->pool);
// Send a request to retrieve the record
if (RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_RECORD,
FCS_OP_RECORD_RETRIEVE)))
{
goto Exit;
}
if (uiContainer)
{
if (RC_BAD( rc = Wire.sendNumber(
WIRE_VALUE_CONTAINER_ID, uiContainer)))
{
goto Transmission_Error;
}
}
if (uiDrn)
{
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_DRN, uiDrn)))
{
goto Transmission_Error;
}
}
if (uiFlag)
{
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiFlag)))
{
goto Transmission_Error;
}
}
if (ppRecord)
{
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_BOOLEAN, TRUE)))
{
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;
}
if( puiDrnRV)
{
*puiDrnRV = Wire.getDrn();
}
if( ppRecord)
{
if( (*ppRecord = Wire.getRecord()) != NULL)
{
(*ppRecord)->AddRef();
}
}
Exit:
pCSContext->pool.poolReset( pvMark);
return( rc);
Transmission_Error:
pCSContext->bConnectionGood = FALSE;
goto Exit;
}