git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
444 lines
8.9 KiB
C++
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;
|
|
}
|