Example #1
0
 INT32 _rtnIXScanner::relocateRID ()
 {
    INT32 rc = SDB_OK ;
    PD_TRACE_ENTRY ( SDB__RTNIXSCAN_RELORID2 ) ;
    monAppCB * pMonAppCB = _cb ? _cb->getMonAppCB() : NULL ;
    // either the key doesn't exist, or we got key/rid not match,
    // or the key is psuedo-deleted, we all get here
    dmsExtentID rootExtent = _indexCB->getRoot() ;
    ixmExtent root ( rootExtent, _su->index() ) ;
    BOOLEAN found ;
    rc = root.locate ( _savedObj, _savedRID, _order, _curIndexRID, found,
                       _direction, _indexCB ) ;
    if ( rc )
    {
       PD_LOG ( PDERROR, "Failed to locate from saved obj and rid: %s, %d,%d",
                _savedObj.toString().c_str(), _savedRID._extent,
                _savedRID._offset ) ;
       goto error ;
    }
    DMS_MON_OP_COUNT_INC( pMonAppCB, MON_INDEX_READ, 1 ) ;
    DMS_MON_CONTEXT_COUNT_INC ( _pMonCtxCB, MON_INDEX_READ, 1 ) ;
 done :
    PD_TRACE_EXITRC ( SDB__RTNIXSCAN_RELORID2, rc ) ;
    return rc ;
 error :
    goto done ;
 }
Example #2
0
   INT32 _rtnIXScanner::relocateRID ( const BSONObj &keyObj,
                                      const dmsRecordID &rid )
   {
      INT32 rc = SDB_OK ;
      PD_TRACE_ENTRY ( SDB__RTNIXSCAN_RELORID1 ) ;

      PD_CHECK ( _indexCB, SDB_OOM, error, PDERROR,
                 "Failed to allocate memory for indexCB" ) ;
      // sanity check, make sure we are on valid index
      PD_CHECK ( _indexCB->isInitialized(), SDB_RTN_INDEX_NOTEXIST, error,
                 PDERROR, "Index does not exist" ) ;
      PD_CHECK ( _indexCB->getFlag() == IXM_INDEX_FLAG_NORMAL,
                 SDB_IXM_UNEXPECTED_STATUS, error, PDERROR,
                 "Unexpected index status: %d", _indexCB->getFlag() ) ;
      {
         monAppCB * pMonAppCB   = _cb ? _cb->getMonAppCB() : NULL ;
         // get root
         dmsExtentID rootExtent = _indexCB->getRoot() ;
         ixmExtent root ( rootExtent, _su->index() ) ;
         BOOLEAN found          = FALSE ;
         // locate the new key, the returned RID is stored in _curIndexRID
         rc = root.locate ( keyObj, rid, _order, _curIndexRID, found,
                            _direction, _indexCB ) ;
         PD_RC_CHECK ( rc, PDERROR,
                       "Failed to locate from new keyobj and rid: %s, %d,%d",
                       keyObj.toString().c_str(), rid._extent,
                       rid._offset ) ;
         _savedObj = keyObj.copy() ;
         _savedRID = rid ;
         DMS_MON_OP_COUNT_INC( pMonAppCB, MON_INDEX_READ, 1 ) ;
         DMS_MON_CONTEXT_COUNT_INC ( _pMonCtxCB, MON_INDEX_READ, 1 ) ;
      }
      // mark _init to true so that advance won't call keyLocate again
      _init = TRUE ;

   done :
      PD_TRACE_EXITRC ( SDB__RTNIXSCAN_RELORID1, rc ) ;
      return rc ;
   error :
      goto done ;
   }
   // PD_TRACE_DECLARE_FUNCTION ( SDB__DMSSTORAGELOADEXT__LDDATA, "dmsStorageLoadOp::loadBuildPhase" )
   INT32 dmsStorageLoadOp::loadBuildPhase ( dmsMBContext *mbContext,
                                            pmdEDUCB *cb,
                                            BOOLEAN isAsynchr,
                                            migMaster *pMaster,
                                            UINT32 *success,
                                            UINT32 *failure )
   {
      INT32 rc = SDB_OK ;
      PD_TRACE_ENTRY ( SDB__DMSSTORAGELOADEXT__LDDATA ) ;

      dmsExtent     *extAddr        = NULL ;
      dmsRecordID    recordID ;
      ossValuePtr    recordPtr      = 0 ;
      ossValuePtr    recordDataPtr  = 0 ;
      ossValuePtr    extentPtr      = 0 ;
      dmsOffset      recordOffset   = DMS_INVALID_OFFSET ;
      dmsExtentID    tempExtentID   = 0 ;
      monAppCB * pMonAppCB          = cb ? cb->getMonAppCB() : NULL ;

      SDB_ASSERT ( _su, "_su can't be NULL" ) ;
      SDB_ASSERT ( mbContext, "dms mb context can't be NULL" ) ;
      SDB_ASSERT ( cb, "cb is NULL" ) ;

      rc = mbContext->mbLock( EXCLUSIVE ) ;
      PD_RC_CHECK( rc, PDERROR, "Failed to lock collection, rc: %d", rc ) ;

      if ( DMS_INVALID_EXTENT == mbContext->mb()->_loadFirstExtentID &&
           DMS_INVALID_EXTENT == mbContext->mb()->_loadLastExtentID )
      {
         PD_LOG ( PDEVENT, "has not load extent" ) ;
         goto done ;
      }

      if ( ( DMS_INVALID_EXTENT == mbContext->mb()->_lastExtentID &&
             DMS_INVALID_EXTENT != mbContext->mb()->_firstExtentID ) ||
           ( DMS_INVALID_EXTENT != mbContext->mb()->_lastExtentID &&
             DMS_INVALID_EXTENT == mbContext->mb()->_firstExtentID ) )
      {
         rc = SDB_SYS ;
         PD_LOG ( PDERROR, "Invalid mb context[%s], first extent: %d, last "
                  "extent: %d", mbContext->toString().c_str(),
                  mbContext->mb()->_firstExtentID,
                  mbContext->mb()->_lastExtentID ) ;
         goto error ;
      }

      clearFlagLoadLoad ( mbContext->mb() ) ;
      setFlagLoadBuild ( mbContext->mb() ) ;

      while ( !cb->isForced() )
      {
         rc = mbContext->mbLock( EXCLUSIVE ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "dms mb context lock failed, rc", rc ) ;
            goto error ;
         }

         tempExtentID = mbContext->mb()->_loadFirstExtentID ;
         if ( DMS_INVALID_EXTENT == tempExtentID )
         {
            mbContext->mb()->_loadFirstExtentID = DMS_INVALID_EXTENT ;
            mbContext->mb()->_loadLastExtentID = DMS_INVALID_EXTENT ;
            goto done ;
         }

         extentPtr = _su->data()->extentAddr( tempExtentID ) ;
         extAddr = (dmsExtent *)extentPtr ;
         PD_CHECK ( extAddr, SDB_SYS, error, PDERROR, "Invalid extent: %d",
                    tempExtentID ) ;
         SDB_ASSERT( extAddr->validate( mbContext->mbID() ),
                     "Invalid extent" ) ;

         rc = _su->data()->addExtent2Meta( tempExtentID, extAddr, mbContext ) ;
         PD_RC_CHECK( rc, PDERROR, "Add extent to meta failed, rc: %d", rc ) ;

         mbContext->mb()->_loadFirstExtentID = extAddr->_nextExtent ;

         extAddr->_firstRecordOffset = DMS_INVALID_OFFSET ;
         extAddr->_lastRecordOffset  = DMS_INVALID_OFFSET ;
         _su->addExtentRecordCount( mbContext->mb(), extAddr->_recCount ) ;
         extAddr->_recCount          = 0 ;
         _su->mapExtent2DelList( mbContext->mb(), extAddr, tempExtentID ) ;

         recordOffset = DMS_EXTENT_METADATA_SZ ;
         recordID._extent = tempExtentID ;

         while ( DMS_INVALID_OFFSET != recordOffset )
         {
            recordPtr = extentPtr + recordOffset ;
            recordID._offset = recordOffset ;
            DMS_RECORD_EXTRACTDATA(recordPtr, recordDataPtr) ;
            recordOffset = DMS_RECORD_GETNEXTOFFSET(recordPtr) ;
            ++( extAddr->_recCount ) ;

            try
            {
               BSONObj obj ( (const CHAR*)recordDataPtr ) ;
               DMS_MON_OP_COUNT_INC( pMonAppCB, MON_DATA_WRITE, 1 ) ;

               rc = _su->index()->indexesInsert( mbContext, tempExtentID, obj,
                                                 recordID, cb ) ;
               if ( rc )
               {
                  if ( SDB_IXM_DUP_KEY != rc )
                  {
                     PD_LOG ( PDERROR, "Failed to insert into index, rc=%d",
                              rc ) ;
                     goto rollback ;
                  }
                  if ( success )
                  {
                     --(*success) ;
                  }
                  if ( failure )
                  {
                     ++(*failure) ;
                  }
                  if ( pMaster )
                  {
                     rc = pMaster->sendMsgToClient( "Error: index insert, error"
                                                    "code %d, %s", rc,
                                                    obj.toString().c_str() ) ;
                     if ( rc )
                     {
                        PD_LOG ( PDERROR, "Failed to send msg, rc=%d", rc ) ;
                     }
                  }
                  rc = _su->data()->deleteRecord ( mbContext, recordID,
                                                   recordDataPtr,
                                                   cb, NULL ) ;
                  if ( rc )
                  {
                     PD_LOG ( PDERROR, "Failed to rollback, rc = %d", rc ) ;
                     goto rollback ;
                  }
               }
            }
            catch ( std::exception &e )
            {
               PD_LOG ( PDERROR, "Failed to create BSON object: %s",
                        e.what() ) ;
               rc = SDB_SYS ;
               goto rollback ;
            }

            if ( DMS_INVALID_OFFSET == extAddr->_firstRecordOffset )
            {
               extAddr->_firstRecordOffset = recordID._offset ;
            }
            extAddr->_lastRecordOffset = recordID._offset ;
         } //while ( DMS_INVALID_OFFSET != recordOffset )

         mbContext->mbUnlock() ;
      } // while

   done:
      PD_TRACE_EXITRC ( SDB__DMSSTORAGELOADEXT__LDDATA, rc );
      return rc ;
   error:
      goto done ;
   rollback:
      recordOffset = recordID._offset ;
      while ( DMS_INVALID_OFFSET != recordOffset )
      {
         recordPtr = extentPtr + recordOffset ;
         recordID._offset = recordOffset ;
         recordOffset = DMS_RECORD_GETNEXTOFFSET(recordPtr) ;

         _su->extentRemoveRecord( mbContext->mb(), recordID, 0, cb ) ;

         if ( DMS_INVALID_OFFSET != recordOffset )
         {
            ++( extAddr->_recCount ) ;
         }
      }
      goto done ;
   }
Example #4
0
   INT32 _rtnIXScanner::advance ( dmsRecordID &rid, BOOLEAN isReadOnly )
   {
      INT32 rc = SDB_OK ;
      PD_TRACE_ENTRY ( SDB__RTNIXSCAN_ADVANCE ) ;
      monAppCB * pMonAppCB = _cb ? _cb->getMonAppCB() : NULL ;
      ixmRecordID lastRID ;

   begin:
      SDB_ASSERT ( _indexCB, "_indexCB can't be NULL, call resumeScan first" ) ;
      // first time run after reset, we need to locate the first key
      if ( !_init )
      {
         // when we get here, we should always hold lock on the collection, so
         // _indexCB should remain valid until pauseScan() and resumeScan(). So
         // in resumeScan() we should always validate if the index still the
         // same
         dmsExtentID rootExtent = _indexCB->getRoot() ;
         ixmExtent root ( rootExtent, _su->index() ) ;
         rc = root.keyLocate ( _curIndexRID, BSONObj(),0,FALSE,
                               _listIterator.cmp(), _listIterator.inc(),
                               _order, _direction, _cb ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "failed to locate first key, rc: %d", rc ) ;
            goto error ;
         }
         _init = TRUE ;
      }
      // otherwise _curIndexRID is pointing to the previous scanned location,
      // we should start from there
      else
      {
         // make sure the current _curIndexRID is not NULL
         if ( _curIndexRID.isNull() )
         {
            // if doing goto here, compile will get error for the following
            // indexExtent object declare
            return SDB_IXM_EOC ;
         }
         ixmExtent indexExtent ( _curIndexRID._extent, _su->index() ) ;
         // in readonly mode, _savedRID should always be NULL unless pauseScan()
         // + resumeScan() found the index structure is changed and we have
         // relocateRID(), in that case _savedRID may not be NULL for readonly
         // mode

         // in write mode, the possible NULL savedRID is that when the
         // previous read is a psuedo-delete, note resumeScan() shouldn't set
         // _savedRID to NULL in this case

         // In such scenario, we advance to next element
         if ( _savedRID.isNull() )
         {
            lastRID = _curIndexRID ;
            // changed during the time
            rc = indexExtent.advance ( _curIndexRID, _direction ) ;
            if ( rc )
            {
               PD_LOG ( PDERROR, "Failed to advance to next key, rc: %d", rc ) ;
               goto error ;
            }
            if ( lastRID == _curIndexRID )
            {
               _curIndexRID.reset() ;
            }
         }
         // need to specially deal with the situation that index tree structure
         // may changed during scan
         // in this case _savedRID can't be NULL
         // advance happened only when both _savedRID and _savedObj matches on
         // disk version
         else if ( !isReadOnly )
         {
            // if it's update or delete index scan, the index structure may get
            // changed so everytime we have to compare _curIndexRID and ondisk
            // rid, as well as the stored object
            dmsRecordID onDiskRID = indexExtent.getRID (
                  _curIndexRID._slot ) ;
            // is the index rid still in valid slot?
            if ( onDiskRID.isNull() )
            {
               // if _curIndexRID is no longer exist, for example if there's
               // page split so that the slot is not pointing to any valid
               // record, let's relocate rid
               rc = relocateRID () ;
               if ( rc )
               {
                  PD_LOG ( PDERROR, "Failed to relocate RID, rc: %d", rc ) ;
                  goto error ;
               }
            }
            // if it's still valid slot, let's see if it matches the last scan
            else if ( onDiskRID == _savedRID )
            {
               // if the RID it's pointing to looks the same, then we need to
               // compare the index key
               CHAR *dataBuffer = indexExtent.getKeyData ( _curIndexRID._slot );
               if ( dataBuffer )
               {
                  try
                  {
                     // get the key that the current RID is pointing to
                     _curKeyObj = ixmKey(dataBuffer).toBson() ;
                     DMS_MON_OP_COUNT_INC( pMonAppCB, MON_INDEX_READ, 1 ) ;
                     DMS_MON_CONTEXT_COUNT_INC ( _pMonCtxCB, MON_INDEX_READ, 1 ) ;
                     // if both on recordRID and key object are the same, let's
                     // say the index is not changed
                     if ( _curKeyObj.shallowEqual(_savedObj) )
                     {
                        // if both key and rid are the same, that means we
                        // should move on to the next
                        rc = indexExtent.advance ( _curIndexRID, _direction ) ;
                        if ( rc )
                        {
                           PD_LOG ( PDERROR, "Failed to advance, rc: %d", rc ) ;
                           goto error ;
                        }
                     }
                     // if the rid are the same but key object not, that means
                     // we got something changed in the index, let's relocate
                     // the RID
                     else
                     {
                        rc = relocateRID () ;
                        if ( rc )
                        {
                           PD_LOG ( PDERROR, "Failed to relocate RID, rc: :%d",
                                    rc ) ;
                           goto error ;
                        }
                     }
                  }
                  catch ( std::exception &e )
                  {
                     PD_LOG ( PDERROR, "Failed to convert buffer to bson from "
                              "current rid: %d,%d: %s", _curIndexRID._extent,
                              _curIndexRID._slot, e.what() ) ;
                     rc = SDB_SYS ;
                     goto error ;
                  }
               } // if ( dataBuffer )
               else
               {
                  PD_LOG ( PDERROR, "Unable to get buffer" ) ;
                  rc = SDB_SYS ;
                  goto error ;
               }
            } // if ( onDiskRID == _savedRID )
            // if the rid are not the same, we must have something changed in
            // the index, let's relocate RID
            else
            {
               rc = relocateRID () ;
               if ( rc )
               {
                  PD_LOG ( PDERROR, "Failed to relocate RID, rc: %d", rc ) ;
                  goto error ;
               }
            }
         } // if ( !isReadOnly )
         // readonly scan with _savedRID not NULL
         else
         {
            // for readonly scan, most of time _savedRID should be NULL, which
            // will not get into this codepath, the only time when we get here
            // is that pauseScan() + resumeScan() found the index structure is
            // changed so _savedRID is NOT reset, which means it called
            // relocateRID() and we should NOT advance to next
            _savedRID.reset() ;
         }
      }
      // after getting the first key location or advanced to next, let's
      // exame if this index key is what we want
      while ( TRUE )
      {
         // after getting _curIndexRID, we have to check if it's null
         if ( _curIndexRID.isNull() )
         {
            // if doing goto here, compile will get error for the following
            // indexExtent object declare
            return SDB_IXM_EOC ;
         }
         // now let's get the binary key and create BSONObj from it
         ixmExtent indexExtent ( _curIndexRID._extent, _su->index() ) ;
         CHAR *dataBuffer = indexExtent.getKeyData ( _curIndexRID._slot ) ;
         if ( !dataBuffer )
         {
            PD_LOG ( PDERROR, "Failed to get buffer from current rid: %d,%d",
                     _curIndexRID._extent, _curIndexRID._slot ) ;
            rc = SDB_SYS ;
            goto error ;
         }
         try
         {
            // get the key from index rid
            try
            {
               _curKeyObj = ixmKey(dataBuffer).toBson() ;
               DMS_MON_OP_COUNT_INC( pMonAppCB, MON_INDEX_READ, 1 ) ;
               DMS_MON_CONTEXT_COUNT_INC ( _pMonCtxCB, MON_INDEX_READ, 1 ) ;
            }
            catch ( std::exception &e )
            {
               PD_RC_CHECK ( SDB_SYS, PDERROR,
                             "Failed to convert from buffer "
                             "to bson, rid: %d,%d: %s",
                             _curIndexRID._extent,
                             _curIndexRID._slot, e.what() ) ;
            }
            // compare the key in list iterator
            rc = _listIterator.advance ( _curKeyObj ) ;
            // if -2, that means we hit end of iterator, so all other keys in
            // index are not within our select range
            if ( -2 == rc )
            {
               rc = SDB_IXM_EOC ;
               goto done ;
            }
            // if >=0, that means the key is not selected and we want to
            // further advance the key in index
            else if ( rc >= 0 )
            {
               lastRID = _curIndexRID ;
               rc = indexExtent.keyAdvance ( _curIndexRID, _curKeyObj, rc,
                                             _listIterator.after(),
                                             _listIterator.cmp(),
                                             _listIterator.inc(),
                                             _order, _direction, _cb ) ;
               PD_RC_CHECK ( rc, PDERROR,
                             "Failed to advance, rc = %d", rc ) ;
               if ( lastRID == _curIndexRID )
               {
                  _curIndexRID.reset() ;
               }
               continue ;
            }
            // otherwise let's attempt to get dms rid
            else
            {
               _savedRID =
                     indexExtent.getRID ( _curIndexRID._slot ) ;
               // make sure the RID we read is not psuedo-deleted
               if ( _savedRID.isNull() ||
                    _dupBuffer.end() != _dupBuffer.find ( _savedRID ) )
               {
                  // usually this means a psuedo-deleted rid, we should jump
                  // back to beginning of the function and advance to next
                  // key

                  // if we are able to find the recordid in dupBuffer, that
                  // means we've already processed the record, so let's also
                  // jump back to begin
                  _savedRID.reset() ;
                  goto begin ;
               }
               // make sure we don't hit maximum size of dedup buffer
               /*if ( _dupBuffer.size() >= _dedupBufferSize )
               {
                  rc = SDB_IXM_DEDUP_BUF_MAX ;
                  goto error ;
               }*/
               _dupBuffer.insert ( _savedRID ) ;
               // ready to return to caller
               rid = _savedRID ;
               // if we are write mode, let's record the _savedObj as well
               if ( !isReadOnly )
               {
                  _savedObj = _curKeyObj.getOwned() ;
               }
               // otherwise if we are read mode, let's reset _savedRID
               else
               {
                  // in readonly scenario, _savedRID should always be null
                  // unless pauseScan() is called
                  _savedRID.reset() ;
               }
               rc = SDB_OK ;
               break ;
            }
         } // try
         catch ( std::exception &e )
         {
            PD_RC_CHECK ( SDB_SYS, PDERROR,
                          "exception during advance index tree: %s",
                          e.what() ) ;
         }
      } // while ( TRUE )
   done :
      PD_TRACE_EXITRC( SDB__RTNIXSCAN_ADVANCE, rc ) ;
      return rc ;
   error :
      goto done ;
   }
Example #5
0
   INT32 _rtnIXScanner::advance ( dmsRecordID &rid, BOOLEAN isReadOnly )
   {
      INT32 rc = SDB_OK ;
      PD_TRACE_ENTRY ( SDB__RTNIXSCAN_ADVANCE ) ;
      monAppCB * pMonAppCB = _cb ? _cb->getMonAppCB() : NULL ;

   begin:
      SDB_ASSERT ( _indexCB, "_indexCB can't be NULL, call resumeScan first" ) ;
      if ( !_init )
      {
         dmsExtentID rootExtent = _indexCB->getRoot() ;
         ixmExtent root ( rootExtent, _su->index() ) ;
         rc = root.keyLocate ( _curIndexRID, BSONObj(),0,FALSE,
                               _listIterator.cmp(), _listIterator.inc(),
                               _order, _direction, _cb ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "failed to locate first key, rc: %d", rc ) ;
            goto error ;
         }
         _init = TRUE ;
      }
      else
      {
         if ( _curIndexRID.isNull() )
         {
            return SDB_IXM_EOC ;
         }
         ixmExtent indexExtent ( _curIndexRID._extent, _su->index() ) ;


         if ( _savedRID.isNull() )
         {
            rc = indexExtent.advance ( _curIndexRID, _direction ) ;
            if ( rc )
            {
               PD_LOG ( PDERROR, "Failed to advance to next key, rc: %d", rc ) ;
               goto error ;
            }
         }
         else if ( !isReadOnly )
         {
            dmsRecordID onDiskRID = indexExtent.getRID (
                  _curIndexRID._slot ) ;
            if ( onDiskRID.isNull() )
            {
               rc = relocateRID () ;
               if ( rc )
               {
                  PD_LOG ( PDERROR, "Failed to relocate RID, rc: %d", rc ) ;
                  goto error ;
               }
            }
            else if ( onDiskRID == _savedRID )
            {
               CHAR *dataBuffer = indexExtent.getKeyData ( _curIndexRID._slot );
               if ( dataBuffer )
               {
                  try
                  {
                     _curKeyObj = ixmKey(dataBuffer).toBson() ;
                     DMS_MON_OP_COUNT_INC( pMonAppCB, MON_INDEX_READ, 1 ) ;
                     DMS_MON_CONTEXT_COUNT_INC ( _pMonCtxCB, MON_INDEX_READ, 1 ) ;
                     if ( _curKeyObj.shallowEqual(_savedObj) )
                     {
                        rc = indexExtent.advance ( _curIndexRID, _direction ) ;
                        if ( rc )
                        {
                           PD_LOG ( PDERROR, "Failed to advance, rc: %d", rc ) ;
                           goto error ;
                        }
                     }
                     else
                     {
                        rc = relocateRID () ;
                        if ( rc )
                        {
                           PD_LOG ( PDERROR, "Failed to relocate RID, rc: :%d",
                                    rc ) ;
                           goto error ;
                        }
                     }
                  }
                  catch ( std::exception &e )
                  {
                     PD_LOG ( PDERROR, "Failed to convert buffer to bson from "
                              "current rid: %d,%d: %s", _curIndexRID._extent,
                              _curIndexRID._slot, e.what() ) ;
                     rc = SDB_SYS ;
                     goto error ;
                  }
               } // if ( dataBuffer )
               else
               {
                  PD_LOG ( PDERROR, "Unable to get buffer" ) ;
                  rc = SDB_SYS ;
                  goto error ;
               }
            } // if ( onDiskRID == _savedRID )
            else
            {
               rc = relocateRID () ;
               if ( rc )
               {
                  PD_LOG ( PDERROR, "Failed to relocate RID, rc: %d", rc ) ;
                  goto error ;
               }
            }
         } // if ( !isReadOnly )
         else
         {
            _savedRID.reset() ;
         }
      }
      while ( TRUE )
      {
         if ( _curIndexRID.isNull() )
         {
            return SDB_IXM_EOC ;
         }
         ixmExtent indexExtent ( _curIndexRID._extent, _su->index() ) ;
         CHAR *dataBuffer = indexExtent.getKeyData ( _curIndexRID._slot ) ;
         if ( !dataBuffer )
         {
            PD_LOG ( PDERROR, "Failed to get buffer from current rid: %d,%d",
                     _curIndexRID._extent, _curIndexRID._slot ) ;
            rc = SDB_SYS ;
            goto error ;
         }
         try
         {
            try
            {
               _curKeyObj = ixmKey(dataBuffer).toBson() ;
               DMS_MON_OP_COUNT_INC( pMonAppCB, MON_INDEX_READ, 1 ) ;
               DMS_MON_CONTEXT_COUNT_INC ( _pMonCtxCB, MON_INDEX_READ, 1 ) ;
            }
            catch ( std::exception &e )
            {
               PD_RC_CHECK ( SDB_SYS, PDERROR,
                             "Failed to convert from buffer "
                             "to bson, rid: %d,%d: %s",
                             _curIndexRID._extent,
                             _curIndexRID._slot, e.what() ) ;
            }
            rc = _listIterator.advance ( _curKeyObj ) ;
            if ( -2 == rc )
            {
               rc = SDB_IXM_EOC ;
               goto done ;
            }
            else if ( rc >= 0 )
            {
               rc = indexExtent.keyAdvance ( _curIndexRID, _curKeyObj, rc,
                                             _listIterator.after(),
                                             _listIterator.cmp(),
                                             _listIterator.inc(),
                                             _order, _direction, _cb ) ;
               PD_RC_CHECK ( rc, PDERROR,
                             "Failed to advance, rc = %d", rc ) ;
               continue ;
            }
            else
            {
               _savedRID =
                     indexExtent.getRID ( _curIndexRID._slot ) ;
               if ( _savedRID.isNull() ||
                    _dupBuffer.end() != _dupBuffer.find ( _savedRID ) )
               {

                  _savedRID.reset() ;
                  goto begin ;
               }
               /*if ( _dupBuffer.size() >= _dedupBufferSize )
               {
                  rc = SDB_IXM_DEDUP_BUF_MAX ;
                  goto error ;
               }*/
               _dupBuffer.insert ( _savedRID ) ;
               rid = _savedRID ;
               if ( !isReadOnly )
               {
                  _savedObj = _curKeyObj.getOwned() ;
               }
               else
               {
                  _savedRID.reset() ;
               }
               rc = SDB_OK ;
               break ;
            }
         } // try
         catch ( std::exception &e )
         {
            PD_RC_CHECK ( SDB_SYS, PDERROR,
                          "exception during advance index tree: %s",
                          e.what() ) ;
         }
      } // while ( TRUE )
   done :
      PD_TRACE_EXITRC( SDB__RTNIXSCAN_ADVANCE, rc ) ;
      return rc ;
   error :
      goto done ;
   }