Added support for large field values (up to 4 GB), async and direct I/O on Linux and Solaris, and performed major code cleanup.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@213 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
@@ -1,319 +1,363 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Index reference splitting routines.
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1991-2000,2002-2006 Novell, Inc. All Rights Reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of version 2 of the GNU General Public
|
||||
// License as published by the Free Software Foundation.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; 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: fsrefspl.cpp 12286 2006-01-19 14:55:18 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
FSTATIC FLMUINT FSSplitRefSet(
|
||||
FLMBYTE * leftBuf,
|
||||
FLMUINT * leftLenRV,
|
||||
FLMBYTE * rightBuf,
|
||||
FLMUINT * rightLenRV,
|
||||
FLMBYTE * refPtr,
|
||||
FLMUINT uiRefLen,
|
||||
FLMUINT uiSplitFactor);
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Try to split a reference set. The size is over the first threshold.
|
||||
If you split this update the b-tree with the new element and position
|
||||
to the current element for insert of the din.
|
||||
Out: The element may be split, or may not. It is not the callers concern.
|
||||
****************************************************************************/
|
||||
RCODE FSRefSplit(
|
||||
FDB * pDb,
|
||||
LFILE * pLFile,
|
||||
BTSK_p * pStackRV, /* Stack area */
|
||||
FLMBYTE * pElmBuf, /* Setup with elements key */
|
||||
FLMUINT din, /* din to insert */
|
||||
FLMUINT uiDeleteFlag, /* Set if you are to delete din */
|
||||
FLMUINT uiSplitFactor) /* Set to SPLIT_90_10 | SPLIT_50_50*/
|
||||
{
|
||||
RCODE rc = FERR_OK; /* Must be set */
|
||||
BTSK_p pStack = *pStackRV; /* Stack may change on you! */
|
||||
FLMBYTE * pCurElm = CURRENT_ELM( pStack );/* Points to current element*/
|
||||
FLMINT iElmLen; /* Length of element in pElmBuf[] */
|
||||
|
||||
FLMBYTE leftBuf[ MAX_REC_ELM ]; /* Left buffer */
|
||||
FLMUINT leftDomain;
|
||||
FLMUINT leftLen;
|
||||
|
||||
FLMBYTE rightBuf[MAX_REC_ELM ]; /* Right (current) buffer */
|
||||
FLMUINT rightDomain;
|
||||
FLMUINT rightLen;
|
||||
|
||||
FLMBYTE * refPtr; /* Points to the references */
|
||||
FLMBYTE * recPtr;
|
||||
FLMUINT uiRefLen; /* Length of references */
|
||||
FLMUINT firstFlag = 0;
|
||||
|
||||
refPtr = pCurElm;
|
||||
recPtr = BBE_REC_PTR( pCurElm );
|
||||
rightDomain = FSGetDomain( &refPtr, (FLMBYTE)pStack->uiElmOvhd );
|
||||
uiRefLen = (FLMUINT)(BBE_GET_RL( pCurElm ) - (FLMUINT)(refPtr - recPtr));
|
||||
FSRS_try_again:
|
||||
leftDomain = FSSplitRefSet( leftBuf, &leftLen, rightBuf, &rightLen,
|
||||
refPtr, uiRefLen, uiSplitFactor );
|
||||
|
||||
if( leftDomain == 0) /* Split failed, setup to add */
|
||||
{
|
||||
/* Try again using a different split factor - OK to fail above */
|
||||
/* In the future, should just handle no splitting and go on */
|
||||
if( uiSplitFactor == SPLIT_50_50)
|
||||
{
|
||||
uiSplitFactor = SPLIT_90_10;
|
||||
goto FSRS_try_again;
|
||||
}
|
||||
#if 0
|
||||
return( RC_SET( FERR_BTREE_ERROR)); /* Can't handle this right now */
|
||||
#else
|
||||
/* Setup for inserting the din into the right buffer and call replace */
|
||||
leftDomain = DIN_DOMAIN(din) + 1;
|
||||
f_memcpy( rightBuf, refPtr, rightLen = uiRefLen );
|
||||
leftLen = 0;
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
*** Write the right element's references.
|
||||
*** Write the right domain if non-zero and replace element
|
||||
**/
|
||||
|
||||
iElmLen = (FLMINT)(BBE_REC_OFS( pElmBuf ));
|
||||
refPtr = recPtr = &pElmBuf[ iElmLen ];
|
||||
if( rightDomain) /* Write the domain if present */
|
||||
{
|
||||
*refPtr++ = SEN_DOMAIN;
|
||||
SENPutNextVal( &refPtr, rightDomain );
|
||||
}
|
||||
|
||||
if( DIN_DOMAIN(din) < leftDomain) /* Remember references DESCEND */
|
||||
{
|
||||
/* Build element inserting the input din */
|
||||
if( uiDeleteFlag)
|
||||
{
|
||||
if( FSSetDeleteRef( refPtr, rightBuf, din, &rightLen))
|
||||
{
|
||||
/* rightLen should not have changed if error found */
|
||||
return ( RC_SET( FERR_KEY_NOT_FOUND) );
|
||||
#if 0
|
||||
f_memcpy( refPtr, rightBuf, rightLen );
|
||||
rc = RC_SET( FERR_KEY_NOT_FOUND); /* Return with this error */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if( FSSetInsertRef( refPtr, rightBuf, din, &rightLen ))
|
||||
{
|
||||
/* Reference there so give up and return success */
|
||||
goto Exit; /* rc is set to FERR_OK */
|
||||
}
|
||||
}
|
||||
else
|
||||
f_memcpy( refPtr, rightBuf, rightLen );
|
||||
|
||||
/* The other flags and lengths are been set by the caller */
|
||||
iElmLen += BBE_SET_RL( pElmBuf, rightLen + (FLMUINT) (refPtr - recPtr ));
|
||||
|
||||
if( BBE_IS_FIRST( pElmBuf ) && leftLen)
|
||||
{
|
||||
firstFlag++;
|
||||
BBE_CLR_FIRST( pElmBuf ); /* Element will no longer be first */
|
||||
|
||||
/* Log the block before modifying it. */
|
||||
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
||||
goto Exit;
|
||||
pCurElm = CURRENT_ELM( pStack );/* Points to current element*/
|
||||
|
||||
BBE_CLR_FIRST( pCurElm ); /* Clear first flag */
|
||||
|
||||
/* Call replace below because FIRST flag is now clear */
|
||||
}
|
||||
|
||||
/* Can call replace because FIRST flag was NOT set */
|
||||
if( RC_BAD( rc = FSBtReplace( pDb, pLFile, &pStack, pElmBuf, iElmLen )))
|
||||
goto Exit;
|
||||
|
||||
/**
|
||||
*** Write the left buffer
|
||||
*** Should be positioned to the right buffer
|
||||
***
|
||||
**/
|
||||
if( leftLen)
|
||||
{
|
||||
/**
|
||||
*** Adjust variables to build and point to the
|
||||
*** left buffers references. Set the domain
|
||||
*** and insert into the b-tree. Then go to the next element
|
||||
**/
|
||||
BBE_CLR_LAST( pElmBuf ); /* Element will no longer be last */
|
||||
if( firstFlag)
|
||||
BBE_SET_FIRST( pElmBuf);
|
||||
iElmLen = (FLMINT)(BBE_REC_OFS( pElmBuf ));
|
||||
refPtr = recPtr = &pElmBuf[ iElmLen ];
|
||||
*refPtr++ = SEN_DOMAIN;
|
||||
SENPutNextVal( &refPtr, leftDomain );
|
||||
|
||||
if( DIN_DOMAIN(din) >= leftDomain)
|
||||
{
|
||||
/* Build element inserting the input din */
|
||||
if( uiDeleteFlag)
|
||||
{
|
||||
if( FSSetDeleteRef( refPtr, leftBuf, din, &leftLen))
|
||||
return( RC_SET( FERR_KEY_NOT_FOUND ));
|
||||
}
|
||||
else
|
||||
/* If this returned with an error code, is alreay in set */
|
||||
if( FSSetInsertRef( refPtr, leftBuf, din, &leftLen ))
|
||||
f_memcpy( refPtr, leftBuf, leftLen );
|
||||
}
|
||||
else
|
||||
f_memcpy( refPtr, leftBuf, leftLen );
|
||||
|
||||
iElmLen += BBE_SET_RL( pElmBuf, leftLen + (FLMUINT) (refPtr - recPtr));
|
||||
|
||||
/* Setup the pStack and bsKeyBuf[] for the insert */
|
||||
|
||||
if( RC_BAD(rc = FSBtScanTo( pStack, &pElmBuf[ BBE_KEY ],
|
||||
(FLMUINT)(BBE_GET_KL(pElmBuf)), 0)))
|
||||
goto Exit;
|
||||
|
||||
rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuf, iElmLen );
|
||||
}
|
||||
Exit:
|
||||
return( rc );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Split a reference set within a domain value. If buffer cannot be
|
||||
split then will return a leftDomain value of ZERO.
|
||||
Must have a minimum of 2 references in left and right buffers.
|
||||
Out: References split to the left or right buffers.
|
||||
Return: 0 if the split failed, else the leftDomain value
|
||||
Notes: Two references are needed in each side because one reference may
|
||||
be deleted leaving the left buffer with a domain & maybe should not.
|
||||
****************************************************************************/
|
||||
FSTATIC FLMUINT FSSplitRefSet(
|
||||
FLMBYTE * leftBuf,
|
||||
FLMUINT * leftLenRV,
|
||||
FLMBYTE * rightBuf,
|
||||
FLMUINT * rightLenRV,
|
||||
FLMBYTE * refPtr,
|
||||
FLMUINT uiRefLen,
|
||||
FLMUINT uiSplitFactor) /* Set to SPLIT_90_10 | SPLIT_50_50*/
|
||||
{
|
||||
FLMUINT leftDomain = 0;
|
||||
FLMUINT din = 0;
|
||||
FLMUINT oneRuns = 0;
|
||||
FLMUINT delta;
|
||||
FLMUINT rightLen;
|
||||
FLMUINT offsetTarget = (uiSplitFactor == SPLIT_90_10)
|
||||
? REF_SPLIT_90_10 : REF_SPLIT_50_50;
|
||||
DIN_STATE leftState, rightState, refState;
|
||||
FLMBYTE byValue;
|
||||
FLMUINT uiLeftCnt;
|
||||
|
||||
RESET_DINSTATE( leftState );
|
||||
RESET_DINSTATE( rightState);
|
||||
RESET_DINSTATE( refState );
|
||||
|
||||
/* Read the first din value */
|
||||
din = DINNextVal( refPtr, &refState );
|
||||
DINPutNextVal( leftBuf, &leftState, din );
|
||||
uiLeftCnt = 1;
|
||||
|
||||
// Must have at least 2 in the left buffer.
|
||||
|
||||
while( refState.uiOffset < offsetTarget || uiLeftCnt < 2)
|
||||
{
|
||||
byValue = refPtr[ refState.uiOffset ];
|
||||
if( DIN_IS_REAL_ONE_RUN( byValue ))
|
||||
{
|
||||
oneRuns = DINOneRunVal( refPtr, &refState );
|
||||
DINPutOneRunVal( leftBuf, &leftState, oneRuns );
|
||||
din -= oneRuns;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = DINNextVal( refPtr, &refState );
|
||||
DINPutNextVal( leftBuf, &leftState, delta );
|
||||
din -= delta;
|
||||
}
|
||||
uiLeftCnt++;
|
||||
}
|
||||
|
||||
/* Made it past the target point - find where domain changes */
|
||||
leftDomain = DIN_DOMAIN( din );
|
||||
|
||||
/* Don't parse past the end */
|
||||
while( refState.uiOffset < uiRefLen)
|
||||
{
|
||||
byValue = refPtr[ refState.uiOffset ];
|
||||
if( DIN_IS_REAL_ONE_RUN( byValue ))
|
||||
{
|
||||
oneRuns = DINOneRunVal( refPtr, &refState );
|
||||
if( DIN_DOMAIN(din-oneRuns) != leftDomain)
|
||||
{
|
||||
/* This is tricky, write only correct number of one runs */
|
||||
delta = din & 0xFF;
|
||||
if( delta)
|
||||
DINPutOneRunVal( leftBuf, &leftState, delta );
|
||||
|
||||
/* Increment delta because setting up for next element */
|
||||
delta++;
|
||||
oneRuns -= delta;
|
||||
/* Write din and one runs below */
|
||||
din -= delta;
|
||||
break;
|
||||
}
|
||||
DINPutOneRunVal( leftBuf, &leftState, oneRuns );
|
||||
din -= oneRuns;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = DINNextVal( refPtr, &refState );
|
||||
din -= delta;
|
||||
if( DIN_DOMAIN(din) != leftDomain)
|
||||
{
|
||||
oneRuns = 0;
|
||||
break;
|
||||
}
|
||||
DINPutNextVal( leftBuf, &leftState, delta );
|
||||
}
|
||||
}
|
||||
if( refState.uiOffset == uiRefLen)
|
||||
return( 0 ); /* Cannot split, caller take care of*/
|
||||
|
||||
/* Start writing to the right side, compare /w uiRefLen proves > 2 refs */
|
||||
DINPutNextVal( rightBuf, &rightState, din );
|
||||
if( oneRuns)
|
||||
DINPutOneRunVal( rightBuf, &rightState, oneRuns );
|
||||
|
||||
*leftLenRV = leftState.uiOffset;
|
||||
rightLen = (FLMUINT)(uiRefLen - refState.uiOffset);
|
||||
|
||||
f_memcpy( &rightBuf[ rightState.uiOffset ],
|
||||
&refPtr[ refState.uiOffset ],
|
||||
rightLen );
|
||||
|
||||
*rightLenRV = rightLen + rightState.uiOffset;
|
||||
|
||||
return( leftDomain );
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Index reference splitting routines.
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1991-2000,2002-2006 Novell, Inc. All Rights Reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of version 2 of the GNU General Public
|
||||
// License as published by the Free Software Foundation.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; 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: fsrefspl.cpp 12286 2006-01-19 14:55:18 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
FSTATIC FLMUINT FSSplitRefSet(
|
||||
FLMBYTE * leftBuf,
|
||||
FLMUINT * leftLenRV,
|
||||
FLMBYTE * rightBuf,
|
||||
FLMUINT * rightLenRV,
|
||||
FLMBYTE * refPtr,
|
||||
FLMUINT uiRefLen,
|
||||
FLMUINT uiSplitFactor);
|
||||
|
||||
/***************************************************************************
|
||||
Desc: Try to split a reference set. The size is over the first threshold.
|
||||
If you split this update the b-tree with the new element and position
|
||||
to the current element for insert of the din.
|
||||
***************************************************************************/
|
||||
RCODE FSRefSplit(
|
||||
FDB * pDb,
|
||||
LFILE * pLFile,
|
||||
BTSK ** pStackRV,
|
||||
FLMBYTE * pElmBuf,
|
||||
FLMUINT din,
|
||||
FLMUINT uiDeleteFlag,
|
||||
FLMUINT uiSplitFactor)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
BTSK * pStack = *pStackRV;
|
||||
FLMBYTE * pCurElm = CURRENT_ELM( pStack);
|
||||
FLMINT iElmLen;
|
||||
FLMBYTE leftBuf[MAX_REC_ELM];
|
||||
FLMUINT leftDomain;
|
||||
FLMUINT leftLen;
|
||||
FLMBYTE rightBuf[MAX_REC_ELM];
|
||||
FLMUINT rightDomain;
|
||||
FLMUINT rightLen;
|
||||
FLMBYTE * refPtr;
|
||||
FLMBYTE * recPtr;
|
||||
FLMUINT uiRefLen;
|
||||
FLMUINT firstFlag = 0;
|
||||
|
||||
refPtr = pCurElm;
|
||||
recPtr = BBE_REC_PTR( pCurElm);
|
||||
rightDomain = FSGetDomain( &refPtr, (FLMBYTE) pStack->uiElmOvhd);
|
||||
uiRefLen = (FLMUINT) (BBE_GET_RL( pCurElm) - (FLMUINT) (refPtr - recPtr));
|
||||
|
||||
FSRS_try_again:
|
||||
|
||||
leftDomain = FSSplitRefSet( leftBuf, &leftLen, rightBuf, &rightLen, refPtr,
|
||||
uiRefLen, uiSplitFactor);
|
||||
|
||||
if (leftDomain == 0)
|
||||
{
|
||||
// Split failed, setup to add
|
||||
//
|
||||
// Try again using a different split factor - OK to fail above;
|
||||
// In the future, should just handle no splitting and go on
|
||||
|
||||
if (uiSplitFactor == SPLIT_50_50)
|
||||
{
|
||||
uiSplitFactor = SPLIT_90_10;
|
||||
goto FSRS_try_again;
|
||||
}
|
||||
|
||||
// Setup for inserting the din into the right buffer and call
|
||||
// replace
|
||||
|
||||
leftDomain = DIN_DOMAIN( din) + 1;
|
||||
f_memcpy( rightBuf, refPtr, rightLen = uiRefLen);
|
||||
leftLen = 0;
|
||||
}
|
||||
|
||||
// Write the right element's references. Write the right domain if
|
||||
// non-zero and replace element
|
||||
|
||||
iElmLen = (FLMINT) (BBE_REC_OFS( pElmBuf));
|
||||
refPtr = recPtr = &pElmBuf[iElmLen];
|
||||
|
||||
if (rightDomain)
|
||||
{
|
||||
*refPtr++ = SEN_DOMAIN;
|
||||
SENPutNextVal( &refPtr, rightDomain);
|
||||
}
|
||||
|
||||
if (DIN_DOMAIN( din) < leftDomain)
|
||||
{
|
||||
|
||||
// Build element inserting the input din
|
||||
|
||||
if (uiDeleteFlag)
|
||||
{
|
||||
if (FSSetDeleteRef( refPtr, rightBuf, din, &rightLen))
|
||||
{
|
||||
|
||||
// rightLen should not have changed if error found
|
||||
|
||||
return (RC_SET( FERR_KEY_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
else if (FSSetInsertRef( refPtr, rightBuf, din, &rightLen))
|
||||
{
|
||||
|
||||
// Reference there so give up and return success
|
||||
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f_memcpy( refPtr, rightBuf, rightLen);
|
||||
}
|
||||
|
||||
// The other flags and lengths are been set by the caller
|
||||
|
||||
iElmLen += BBE_SET_RL( pElmBuf, rightLen + (FLMUINT) (refPtr - recPtr));
|
||||
|
||||
if (BBE_IS_FIRST( pElmBuf) && leftLen)
|
||||
{
|
||||
firstFlag++;
|
||||
BBE_CLR_FIRST( pElmBuf);
|
||||
|
||||
// Log the block before modifying it.
|
||||
|
||||
if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pCurElm = CURRENT_ELM( pStack);
|
||||
BBE_CLR_FIRST( pCurElm);
|
||||
|
||||
// Call replace below because FIRST flag is now clear
|
||||
}
|
||||
|
||||
// Can call replace because FIRST flag was NOT set
|
||||
|
||||
if (RC_BAD( rc = FSBtReplace( pDb, pLFile, &pStack, pElmBuf, iElmLen)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Write the left buffer Should be positioned to the right buffer
|
||||
|
||||
if (leftLen)
|
||||
{
|
||||
|
||||
// Adjust variables to build and point to the left buffers
|
||||
// references. Set the domain and insert into the b-tree. Then go to
|
||||
// the next element
|
||||
|
||||
BBE_CLR_LAST( pElmBuf);
|
||||
if (firstFlag)
|
||||
{
|
||||
BBE_SET_FIRST( pElmBuf);
|
||||
}
|
||||
|
||||
iElmLen = (FLMINT) (BBE_REC_OFS( pElmBuf));
|
||||
refPtr = recPtr = &pElmBuf[iElmLen];
|
||||
*refPtr++ = SEN_DOMAIN;
|
||||
SENPutNextVal( &refPtr, leftDomain);
|
||||
|
||||
if (DIN_DOMAIN( din) >= leftDomain)
|
||||
{
|
||||
|
||||
// Build element inserting the input din
|
||||
|
||||
if (uiDeleteFlag)
|
||||
{
|
||||
if (FSSetDeleteRef( refPtr, leftBuf, din, &leftLen))
|
||||
{
|
||||
return (RC_SET( FERR_KEY_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FSSetInsertRef( refPtr, leftBuf, din, &leftLen))
|
||||
{
|
||||
f_memcpy( refPtr, leftBuf, leftLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f_memcpy( refPtr, leftBuf, leftLen);
|
||||
}
|
||||
|
||||
iElmLen += BBE_SET_RL( pElmBuf, leftLen + (FLMUINT) (refPtr - recPtr));
|
||||
|
||||
// Setup the pStack and bsKeyBuf[] for the insert
|
||||
|
||||
if (RC_BAD( rc = FSBtScanTo( pStack, &pElmBuf[BBE_KEY],
|
||||
(FLMUINT) (BBE_GET_KL( pElmBuf)), 0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuf, iElmLen);
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: Split a reference set within a domain value. If buffer cannot be
|
||||
split then will return a leftDomain value of ZERO. Must have a
|
||||
minimum of 2 references in left and right buffers.
|
||||
***************************************************************************/
|
||||
FSTATIC FLMUINT FSSplitRefSet(
|
||||
FLMBYTE * leftBuf,
|
||||
FLMUINT * leftLenRV,
|
||||
FLMBYTE * rightBuf,
|
||||
FLMUINT * rightLenRV,
|
||||
FLMBYTE * refPtr,
|
||||
FLMUINT uiRefLen,
|
||||
FLMUINT uiSplitFactor)
|
||||
{
|
||||
FLMUINT leftDomain = 0;
|
||||
FLMUINT din = 0;
|
||||
FLMUINT oneRuns = 0;
|
||||
FLMUINT delta;
|
||||
FLMUINT rightLen;
|
||||
FLMUINT offsetTarget;
|
||||
DIN_STATE leftState;
|
||||
DIN_STATE rightState;
|
||||
DIN_STATE refState;
|
||||
FLMBYTE byValue;
|
||||
FLMUINT uiLeftCnt;
|
||||
|
||||
RESET_DINSTATE( leftState);
|
||||
RESET_DINSTATE( rightState);
|
||||
RESET_DINSTATE( refState);
|
||||
|
||||
offsetTarget = (uiSplitFactor == SPLIT_90_10)
|
||||
? REF_SPLIT_90_10
|
||||
: REF_SPLIT_50_50;
|
||||
|
||||
// Read the first din value
|
||||
|
||||
din = DINNextVal( refPtr, &refState);
|
||||
DINPutNextVal( leftBuf, &leftState, din);
|
||||
uiLeftCnt = 1;
|
||||
|
||||
// Must have at least 2 in the left buffer.
|
||||
|
||||
while (refState.uiOffset < offsetTarget || uiLeftCnt < 2)
|
||||
{
|
||||
byValue = refPtr[refState.uiOffset];
|
||||
if (DIN_IS_REAL_ONE_RUN( byValue))
|
||||
{
|
||||
oneRuns = DINOneRunVal( refPtr, &refState);
|
||||
DINPutOneRunVal( leftBuf, &leftState, oneRuns);
|
||||
din -= oneRuns;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = DINNextVal( refPtr, &refState);
|
||||
DINPutNextVal( leftBuf, &leftState, delta);
|
||||
din -= delta;
|
||||
}
|
||||
|
||||
uiLeftCnt++;
|
||||
}
|
||||
|
||||
// Made it past the target point - find where domain changes
|
||||
|
||||
leftDomain = DIN_DOMAIN( din);
|
||||
|
||||
// Don't parse past the end
|
||||
|
||||
while (refState.uiOffset < uiRefLen)
|
||||
{
|
||||
byValue = refPtr[refState.uiOffset];
|
||||
if (DIN_IS_REAL_ONE_RUN( byValue))
|
||||
{
|
||||
oneRuns = DINOneRunVal( refPtr, &refState);
|
||||
if (DIN_DOMAIN( din - oneRuns) != leftDomain)
|
||||
{
|
||||
|
||||
// This is tricky, write only correct number of one runs
|
||||
|
||||
delta = din & 0xFF;
|
||||
if (delta)
|
||||
{
|
||||
DINPutOneRunVal( leftBuf, &leftState, delta);
|
||||
}
|
||||
|
||||
// Increment delta because setting up for next element
|
||||
|
||||
delta++;
|
||||
oneRuns -= delta;
|
||||
|
||||
// Write din and one runs below
|
||||
|
||||
din -= delta;
|
||||
break;
|
||||
}
|
||||
|
||||
DINPutOneRunVal( leftBuf, &leftState, oneRuns);
|
||||
din -= oneRuns;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = DINNextVal( refPtr, &refState);
|
||||
din -= delta;
|
||||
if (DIN_DOMAIN( din) != leftDomain)
|
||||
{
|
||||
oneRuns = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
DINPutNextVal( leftBuf, &leftState, delta);
|
||||
}
|
||||
}
|
||||
|
||||
if (refState.uiOffset == uiRefLen)
|
||||
{
|
||||
// Cannot split, caller take care of
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Start writing to the right side, compare /w uiRefLen proves > 2 refs
|
||||
|
||||
DINPutNextVal( rightBuf, &rightState, din);
|
||||
if (oneRuns)
|
||||
{
|
||||
DINPutOneRunVal( rightBuf, &rightState, oneRuns);
|
||||
}
|
||||
|
||||
*leftLenRV = leftState.uiOffset;
|
||||
rightLen = (FLMUINT) (uiRefLen - refState.uiOffset);
|
||||
|
||||
f_memcpy( &rightBuf[rightState.uiOffset], &refPtr[refState.uiOffset],
|
||||
rightLen);
|
||||
|
||||
*rightLenRV = rightLen + rightState.uiOffset;
|
||||
return (leftDomain);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user