Blame lib/Mrm/MrmIindexw.c

Packit b099d7
/* 
Packit b099d7
 * Motif
Packit b099d7
 *
Packit b099d7
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are free software; you can
Packit b099d7
 * redistribute them and/or modify them under the terms of the GNU
Packit b099d7
 * Lesser General Public License as published by the Free Software
Packit b099d7
 * Foundation; either version 2 of the License, or (at your option)
Packit b099d7
 * any later version.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are distributed in the hope that
Packit b099d7
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
Packit b099d7
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Packit b099d7
 * PURPOSE. See the GNU Lesser General Public License for more
Packit b099d7
 * details.
Packit b099d7
 *
Packit b099d7
 * You should have received a copy of the GNU Lesser General Public
Packit b099d7
 * License along with these librararies and programs; if not, write
Packit b099d7
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
Packit b099d7
 * Floor, Boston, MA 02110-1301 USA
Packit b099d7
 */ 
Packit b099d7
/* 
Packit b099d7
 * HISTORY
Packit b099d7
 */ 
Packit b099d7
#ifdef HAVE_CONFIG_H
Packit b099d7
#include <config.h>
Packit b099d7
#endif
Packit b099d7
Packit b099d7
Packit b099d7
#ifdef REV_INFO
Packit b099d7
#ifndef lint
Packit b099d7
static char rcsid[] = "$XConsortium: MrmIindexw.c /main/12 1996/11/13 13:57:54 drk $"
Packit b099d7
#endif
Packit b099d7
#endif
Packit b099d7
Packit b099d7
/* (c) Copyright 1989, 1990, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */
Packit b099d7
Packit b099d7
Packit b099d7
Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *  FACILITY:
Packit b099d7
 *
Packit b099d7
 *      UIL Resource Manager (URM): IDB Facility
Packit b099d7
 *	Index management routines
Packit b099d7
 *
Packit b099d7
 *  ABSTRACT:
Packit b099d7
 *
Packit b099d7
 *	These routines manage the index of an IDB file, including 
Packit b099d7
 *	retrieving data entries accessed by index, and maintaing the
Packit b099d7
 *	index structure, particularly index splitting
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Packit b099d7
/*
Packit b099d7
 *
Packit b099d7
 *  INCLUDE FILES
Packit b099d7
 *
Packit b099d7
 */
Packit b099d7
Packit b099d7
#include <Mrm/MrmAppl.h>
Packit b099d7
#include <Mrm/Mrm.h>
Packit b099d7
#include <Mrm/IDB.h>
Packit b099d7
#include "MrmMsgI.h"
Packit b099d7
Packit b099d7
Packit b099d7
/*
Packit b099d7
 *
Packit b099d7
 *  TABLE OF CONTENTS
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_EnterItem		- Enter a data entry under an index
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_EnterLeafIndex		- Add an entry to a leaf record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_EnterNodeIndex		- Add an entry to a node record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_SplitLeafRecord	- Split a leaf index record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_SplitNodeRecord	- Split a node index record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_InitRootLeafRecord	- Init a (root) leaf index record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_InitRootNodeRecord	- Init a (root) node index record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_CopyLeafRecord		- Copy a leaf record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_CopyNodeRecord		- Copy a node record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_CollapseLeafRecord	- Collapse a leaf record (truncate)
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_CollapseNodeRecord	- Collapse a node record (truncate)
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_ConfirmNodeSpace	- Confirm enough space in node
Packit b099d7
 *					  record for new entry
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_SetParent		- Set parent pointer in record
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_FixNodeChildren	- Reset parent pointers for all
Packit b099d7
 *					  the children of some node
Packit b099d7
 *
Packit b099d7
 */
Packit b099d7
Packit b099d7
Packit b099d7
/*
Packit b099d7
 *
Packit b099d7
 *  DEFINE and MACRO DEFINITIONS
Packit b099d7
 *
Packit b099d7
 */
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Macros which validate index records in buffers
Packit b099d7
 */
Packit b099d7
#define	Idb__INX_ValidLeaf(buffer) \
Packit b099d7
     (_IdbBufferRecordType(buffer)==IDBrtIndexLeaf)
Packit b099d7
#define	Idb__INX_ValidNode(buffer) \
Packit b099d7
     (_IdbBufferRecordType(buffer)==IDBrtIndexNode)
Packit b099d7
#define	Idb__INX_ValidRecord(buffer) \
Packit b099d7
     (_IdbBufferRecordType(buffer)==IDBrtIndexLeaf ||  \
Packit b099d7
      _IdbBufferRecordType(buffer)==IDBrtIndexNode)
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_EnterItem makes an entry in the file's index for a data
Packit b099d7
 *	entry which has been previously entered in the file.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file in which to write entry
Packit b099d7
 *	index		The entry's case-sensitive index
Packit b099d7
 *	data_entry	Data entry pointer for data
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmEXISTS	index already exists in file
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_EnterItem (IDBFile		file_id ,
Packit b099d7
		    char		*index ,
Packit b099d7
		    IDBDataHandle	data_entry )
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordBufferPtr	bufptr ;	/* buffer into which to stuff entry */
Packit b099d7
  MrmCount		entndx ;	/* locates pivotal entry in buffer */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize the index with this entry if this is the initial one.
Packit b099d7
   */
Packit b099d7
  if ( !file_id->index_root )
Packit b099d7
    {
Packit b099d7
      result = Idb__INX_InitRootLeafRecord (file_id, &bufptr) ;
Packit b099d7
      if (result != MrmSUCCESS ) return result ;
Packit b099d7
      result = Idb__INX_EnterLeafIndex
Packit b099d7
        (file_id, bufptr, index, data_entry, 0, MrmINDEX_LT) ;
Packit b099d7
      return result ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Find the (leaf) record in which to place this entry, and the
Packit b099d7
   * position in the record. Place it in the record (which must be
Packit b099d7
   * a leaf record). This process loops as long as record splitting
Packit b099d7
   * forces retries.
Packit b099d7
   */
Packit b099d7
  do  {
Packit b099d7
    result = Idb__INX_FindIndex (file_id, index, &bufptr, &entndx) ;
Packit b099d7
    switch ( result )
Packit b099d7
      {
Packit b099d7
      case MrmINDEX_GT:
Packit b099d7
      case MrmINDEX_LT:
Packit b099d7
	break ;
Packit b099d7
      case MrmSUCCESS:
Packit b099d7
	return MrmEXISTS ;
Packit b099d7
      default:
Packit b099d7
	return result ;
Packit b099d7
      }
Packit b099d7
    result = Idb__INX_EnterLeafIndex
Packit b099d7
      (file_id, bufptr, index, data_entry, entndx, result) ;
Packit b099d7
  } while ( result == MrmINDEX_RETRY ) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Return results of final attempt to stuff in a leaf record
Packit b099d7
   */
Packit b099d7
  return result ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_EnterLeafIndex creates a new entry for a data entry in a
Packit b099d7
 *	leaf index record. If there isn't enough room in the record for
Packit b099d7
 *	the new entry, the record is split and the enter operation must
Packit b099d7
 *	be retried.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	buffer		Buffer containing leaf index record
Packit b099d7
 *	index		The entry's case-sensitive index
Packit b099d7
 *	data_entry	Data entry pointer for data
Packit b099d7
 *	entry_index	Entry in record at which to force new entry
Packit b099d7
 *	order		Specifies how new entry orders WRT entry at
Packit b099d7
 *			entry_index; MrmINDEX_GT or MrmINDEX_LT.
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmINDEX_RETRY	operation must be tried again.
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_EnterLeafIndex (IDBFile		file_id,
Packit b099d7
			 IDBRecordBufferPtr	buffer,
Packit b099d7
			 char			*index,
Packit b099d7
			 IDBDataHandle		data_entry,
Packit b099d7
			 MrmCount		entry_index,
Packit b099d7
			 Cardinal		order)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBIndexLeafRecordPtr	recptr ;	/* leaf record in buffer */
Packit b099d7
  IDBIndexLeafHdrPtr	hdrptr ;	/* record header */
Packit b099d7
  MrmCount		entndx ;	/* index for new entry */
Packit b099d7
  Cardinal		entsiz ;	/* # bytes needed for new entry */
Packit b099d7
  MrmCount		ndxsiz ;	/* # bytes needed for new string */
Packit b099d7
  char			*ndxstg ;	/* location for new string */
Packit b099d7
  int			ndx ;		/* loop index */
Packit b099d7
  char			*stgheap ;	/* string heap beginning */
Packit b099d7
  MrmCount		nfree ;		/* # free bytes */
Packit b099d7
  IDBIndexLeafEntryPtr	itemvec ;	/* The vector of index entries */
Packit b099d7
  MrmCount		itemcnt ;	/* # entries in vector */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize pointers into the record
Packit b099d7
   */
Packit b099d7
  recptr = (IDBIndexLeafRecordPtr) buffer->IDB_record ;
Packit b099d7
  hdrptr = (IDBIndexLeafHdrPtr) &recptr->leaf_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Compute sizes for new entry. Split record and retry if required
Packit b099d7
   * to get enough space.
Packit b099d7
   */
Packit b099d7
  ndxsiz = MIN(strlen(index),IDBMaxIndexLength) + 1 ;
Packit b099d7
  ndxsiz = _FULLWORD(ndxsiz);
Packit b099d7
  entsiz = IDBIndexLeafEntrySize + ndxsiz ;
Packit b099d7
  nfree = hdrptr->free_bytes ;
Packit b099d7
  if ( entsiz > nfree )
Packit b099d7
    {
Packit b099d7
      result = Idb__INX_SplitLeafRecord (file_id, buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      return MrmINDEX_RETRY ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Pick up values and pointers into the record.
Packit b099d7
   * Adjust entry index based on ordering, then make room for the
Packit b099d7
   * new entry.
Packit b099d7
   */
Packit b099d7
  stgheap = (char *) &recptr->index[0] + hdrptr->heap_start ;
Packit b099d7
  itemvec = recptr->index ;
Packit b099d7
  itemcnt = hdrptr->index_count ;
Packit b099d7
Packit b099d7
  entndx = (order==MrmINDEX_GT) ? entry_index+1 : entry_index ;
Packit b099d7
  ndxstg = (char *) stgheap - ndxsiz ;
Packit b099d7
Packit b099d7
  for ( ndx=itemcnt ; ndx>entndx ; ndx--)
Packit b099d7
    {
Packit b099d7
      itemvec[ndx].index_stg = itemvec[ndx-1].index_stg ;
Packit b099d7
      itemvec[ndx].data = itemvec[ndx-1].data ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Move the string and set the values in the vector entry
Packit b099d7
   */
Packit b099d7
  strcpy (ndxstg, "") ;
Packit b099d7
  strncat (ndxstg, index, IDBMaxIndexLength) ;
Packit b099d7
  itemvec[entndx].index_stg = (MrmOffset) (ndxstg-(char *)itemvec) ;
Packit b099d7
  itemvec[entndx].data.internal_id.rec_no = data_entry.rec_no ;
Packit b099d7
  itemvec[entndx].data.internal_id.item_offs = data_entry.item_offs ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * update the header
Packit b099d7
   */
Packit b099d7
  hdrptr->index_count++ ;
Packit b099d7
  hdrptr->heap_start -= ndxsiz ;
Packit b099d7
  hdrptr->free_bytes -= entsiz ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * entry successfully added
Packit b099d7
   */
Packit b099d7
  Idb__BM_MarkModified (buffer) ;
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_EnterNodeIndex creates a new entry for a data entry in a
Packit b099d7
 *	node index record. It differs from entering an item in a leaf record
Packit b099d7
 *	in that the position for the new entry is not known.
Packit b099d7
 *	If there isn't room for the new entry, the record is split, and
Packit b099d7
 *	the operation must be tried again.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	buffer		Buffer containing node index record
Packit b099d7
 *	index		The entry's case-sensitive index
Packit b099d7
 *	data_entry	Data entry pointer for data
Packit b099d7
 *	lt_record	Record number of the less-than record associated with
Packit b099d7
 *			this entry
Packit b099d7
 *	gt_record	Record number of the greater-than record associated with
Packit b099d7
 *			this entry
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmINDEX_RETRY	operation must be tried again.
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_EnterNodeIndex (IDBFile		file_id,
Packit b099d7
			 IDBRecordBufferPtr	buffer,
Packit b099d7
			 char			*index,
Packit b099d7
			 IDBDataHandle		data_entry,
Packit b099d7
			 IDBRecordNumber	lt_record,
Packit b099d7
			 IDBRecordNumber	gt_record)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBIndexNodeRecordPtr	recptr ;	/* node record in buffer */
Packit b099d7
  IDBIndexNodeHdrPtr	hdrptr ;	/* record header */
Packit b099d7
  MrmCount		entry_index ;	/* searched location for new entry */
Packit b099d7
  Cardinal		order ;		/* order of index WRT location */
Packit b099d7
  MrmCount		entndx ;	/* index for new entry */
Packit b099d7
  Cardinal		entsiz ;	/* # bytes needed for new entry */
Packit b099d7
  MrmCount		ndxsiz ;	/* # bytes needed for new string */
Packit b099d7
  char			*ndxstg ;	/* location for new string */
Packit b099d7
  int			ndx ;		/* loop index */
Packit b099d7
  char			*stgheap ;	/* string heap beginning */
Packit b099d7
  MrmCount		nfree ;		/* # free bytes */
Packit b099d7
  IDBIndexNodeEntryPtr	itemvec ;	/* The vector of index entries */
Packit b099d7
  MrmCount		itemcnt ;	/* # entries in vector */
Packit b099d7
  MrmCount		prvndx ;	/* preceding entry index */
Packit b099d7
  MrmCount		nxtndx ;	/* succeeding entry index */
Packit b099d7
  IDBRecordNumber	p_recno ;	/* this node record number */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize pointers into the record
Packit b099d7
   */
Packit b099d7
  recptr = (IDBIndexNodeRecordPtr) buffer->IDB_record ;
Packit b099d7
  hdrptr = (IDBIndexNodeHdrPtr) &recptr->node_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Compute sizes for new entry. Split record and retry if required
Packit b099d7
   * to get enough space.
Packit b099d7
   */
Packit b099d7
  ndxsiz = MIN(strlen(index),IDBMaxIndexLength) + 1 ;
Packit b099d7
  ndxsiz = _FULLWORD(ndxsiz);
Packit b099d7
  entsiz = IDBIndexNodeEntrySize + ndxsiz ;
Packit b099d7
  nfree = hdrptr->free_bytes ;
Packit b099d7
  if ( entsiz > nfree )
Packit b099d7
    {
Packit b099d7
      result = Idb__INX_SplitNodeRecord (file_id, buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      return MrmINDEX_RETRY ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Pick up value and pointers into the record. Figure out the
Packit b099d7
   * location at which to insert the record (0 for a new entry),
Packit b099d7
   * and make room for the new entry.
Packit b099d7
   */
Packit b099d7
  stgheap = (char *) &recptr->index[0] + hdrptr->heap_start ;
Packit b099d7
  itemvec = recptr->index ;
Packit b099d7
  itemcnt = hdrptr->index_count ;
Packit b099d7
  if ( itemcnt == 0 )
Packit b099d7
    entndx = 0 ;
Packit b099d7
  else
Packit b099d7
    {
Packit b099d7
      order = Idb__INX_SearchIndex (file_id, index, buffer, &entry_index) ;
Packit b099d7
      entndx = (order==MrmINDEX_GT) ? entry_index+1 : entry_index ;
Packit b099d7
      for ( ndx=itemcnt ; ndx>entndx ; ndx--)
Packit b099d7
        {
Packit b099d7
	  itemvec[ndx].index_stg = itemvec[ndx-1].index_stg ;
Packit b099d7
	  itemvec[ndx].data = itemvec[ndx-1].data ;
Packit b099d7
	  itemvec[ndx].LT_record = itemvec[ndx-1].LT_record ;
Packit b099d7
	  itemvec[ndx].GT_record = itemvec[ndx-1].GT_record ;
Packit b099d7
        }
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Move the string and set the values in the vector entry and record vector
Packit b099d7
   */
Packit b099d7
  ndxstg = (char *) stgheap - ndxsiz ;
Packit b099d7
  strcpy (ndxstg, "") ;
Packit b099d7
  strncat (ndxstg, index, IDBMaxIndexLength) ;
Packit b099d7
  itemvec[entndx].index_stg = (MrmOffset) (ndxstg-(char *)itemvec) ;
Packit b099d7
  itemvec[entndx].data.internal_id.rec_no = data_entry.rec_no ;
Packit b099d7
  itemvec[entndx].data.internal_id.item_offs = data_entry.item_offs ;
Packit b099d7
  itemvec[entndx].LT_record = lt_record ;
Packit b099d7
  itemvec[entndx].GT_record = gt_record ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * update the header
Packit b099d7
   */
Packit b099d7
  hdrptr->index_count = ++itemcnt ;
Packit b099d7
  hdrptr->heap_start -= ndxsiz ;
Packit b099d7
  hdrptr->free_bytes -= entsiz ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Now the entries to either side of the new index must have their LT
Packit b099d7
   * and LT pointers verified and changed. By practice, the GT record of the
Packit b099d7
   * new entry is a previous record which should occur as the GT record of
Packit b099d7
   * the preceding entry and the LT record of the succeeding entry.
Packit b099d7
   * These entries must be modified to have LT and GT pointers matching the
Packit b099d7
   * records given here as arguments.
Packit b099d7
   */
Packit b099d7
  if ( entndx > 0 )
Packit b099d7
    {
Packit b099d7
      prvndx = entndx - 1 ;
Packit b099d7
      if ( itemvec[prvndx].GT_record != gt_record )
Packit b099d7
        return Urm__UT_Error ("Idb__INX_EnterNodeIndex", _MrmMMsg_0016,
Packit b099d7
			      file_id, NULL, MrmBAD_BTREE) ;
Packit b099d7
      itemvec[prvndx].GT_record = lt_record ;
Packit b099d7
    }
Packit b099d7
  if ( entndx < (itemcnt-1) )
Packit b099d7
    {
Packit b099d7
      nxtndx = entndx + 1 ;
Packit b099d7
      if ( itemvec[nxtndx].LT_record != gt_record )
Packit b099d7
        return Urm__UT_Error ("Idb__INX_EnterNodeIndex", _MrmMMsg_0017,
Packit b099d7
			      file_id, NULL, MrmBAD_BTREE) ;
Packit b099d7
      itemvec[nxtndx].LT_record = gt_record ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * entry successfully added
Packit b099d7
   */
Packit b099d7
  Idb__BM_MarkModified (buffer) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Set the parent pointer in the LT  and GT records
Packit b099d7
   */
Packit b099d7
  p_recno = _IdbBufferRecordNumber (buffer) ;
Packit b099d7
  result = Idb__INX_SetParent (file_id, p_recno, lt_record) ;
Packit b099d7
  result = Idb__INX_SetParent (file_id, p_recno, gt_record) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_SplitRecord splits an index record in order to make room
Packit b099d7
 *	for new entries. This is the crucial routine in causing the B-tree
Packit b099d7
 *	to grow. It splits leaf records only.
Packit b099d7
 *
Packit b099d7
 *	The split process takes place as follows:
Packit b099d7
 *		- extract the middle entry from the record and save it.
Packit b099d7
 *		- create a new leaf record and move all the less-than
Packit b099d7
 *		  ordered entries into it.
Packit b099d7
 *		- reorganize the current record to contain only the greater-than
Packit b099d7
 *		  ordered entries (garbage collecting the string heap).
Packit b099d7
 *		- Enter the extracted entry in the parent (creating a new
Packit b099d7
 *		  parent if required). This entry takes the less-than
Packit b099d7
 *		  record with it to the parent, thus entering the new leaf
Packit b099d7
 *		  record in the B-tree. The old record is retained as a
Packit b099d7
 *		  greater-than record for the extracted index.
Packit b099d7
 *
Packit b099d7
 *	The trickiest aspect of splitting nodes is maintaining parent
Packit b099d7
 *	pointers when splitting may cause parents to change. IDB deals
Packit b099d7
 *	this by splitting from the top of the tree down, so that a node's
Packit b099d7
 *	parent pointer is guaranteed correct when the node is split.
Packit b099d7
 *	This is done by:
Packit b099d7
 *		- Before splitting, check that parent has enough room
Packit b099d7
 *		  for a new entry. If not, the parent will split and
Packit b099d7
 *		  inform the caller to retry.
Packit b099d7
 *		- Splitting the root node is always safe
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	gt_buffer	Buffer containing leaf index record to be split
Packit b099d7
 *			This will become the new GT buffer
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmBAD_RECORD	not a leaf index record
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_SplitLeafRecord (IDBFile		file_id,
Packit b099d7
			  IDBRecordBufferPtr	gt_buffer)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordNumber	p_recno ;	/* parent record number */
Packit b099d7
  IDBRecordBufferPtr	p_buffer ;	/* parent buffer */
Packit b099d7
  IDBRecordBufferPtr	lt_buffer ;	/* buffer for LT leaf record */
Packit b099d7
  IDBIndexLeafRecordPtr	lt_recptr ;	/* LT leaf record in buffer */
Packit b099d7
  IDBIndexLeafRecordPtr	gt_recptr ;	/* GT leaf record in buffer */
Packit b099d7
  IDBIndexLeafHdrPtr	gt_hdrptr ;	/* GT record header */
Packit b099d7
  MrmCount		p_index ;	/* index of hoisted entry */
Packit b099d7
  char			p_index_stg[IDBMaxIndexLength1] ; /* save hoisted idx */
Packit b099d7
  char			*p_index_stgadr ;  /* Address of hoisted index string */
Packit b099d7
  IDBDataHandle		p_data ;	/* saves hoisted entry data */
Packit b099d7
  MrmCount		lt_cnt ;	/* number of LT items */
Packit b099d7
  MrmCount		gt_cnt ;	/* number of GT items */
Packit b099d7
  MrmCount		old_cnt ;	/* original number of items */
Packit b099d7
  IDBIndexLeafEntryPtr	old_itmvec ;	/* Original vector */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize pointers into the record and sanity check. This record
Packit b099d7
   * will become the GT leaf record
Packit b099d7
   */
Packit b099d7
  if ( ! Idb__INX_ValidLeaf(gt_buffer) )
Packit b099d7
    return Urm__UT_Error ("Idb__INX_SplitLeafRecord", _MrmMMsg_0010,
Packit b099d7
			  file_id, NULL, MrmBAD_RECORD) ;
Packit b099d7
Packit b099d7
  gt_recptr = (IDBIndexLeafRecordPtr) gt_buffer->IDB_record ;
Packit b099d7
  gt_hdrptr = (IDBIndexLeafHdrPtr) &gt_recptr->leaf_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * If this node has a parent, make sure it can hold a new entry.
Packit b099d7
   * If not, it will split, and we must retry. Note a parent must be
Packit b099d7
   * a node record.
Packit b099d7
   */
Packit b099d7
  p_recno = gt_hdrptr->parent ;
Packit b099d7
  if ( gt_hdrptr->parent )
Packit b099d7
    {
Packit b099d7
      result = Idb__BM_GetRecord (file_id, gt_hdrptr->parent, &p_buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      if ( ! Idb__INX_ValidNode(p_buffer) )
Packit b099d7
        return Urm__UT_Error ("Idb__INX_SplitLeafRecord", _MrmMMsg_0018,
Packit b099d7
			      file_id, NULL, MrmBAD_RECORD) ;
Packit b099d7
      result = Idb__INX_ConfirmNodeSpace (file_id, p_buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Pick up current parameters
Packit b099d7
   */
Packit b099d7
  old_cnt = gt_hdrptr->index_count ;
Packit b099d7
  old_itmvec = gt_recptr->index ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Compute the indexes and counts for the split, and save the hoisted entry.
Packit b099d7
   */
Packit b099d7
  lt_cnt = old_cnt / 2 ;
Packit b099d7
  p_index = lt_cnt ;
Packit b099d7
  gt_cnt = old_cnt - lt_cnt - 1;
Packit b099d7
  p_index_stgadr = (char *) old_itmvec+old_itmvec[p_index].index_stg ;
Packit b099d7
  strcpy (p_index_stg, p_index_stgadr) ;
Packit b099d7
  p_data.rec_no = old_itmvec[p_index].data.internal_id.rec_no ;
Packit b099d7
  p_data.item_offs = old_itmvec[p_index].data.internal_id.item_offs ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Acquire a new record to become the LT part. Copy the entire current
Packit b099d7
   * record into it, then collapse both records into their final form.
Packit b099d7
   */
Packit b099d7
  result = Idb__BM_InitRecord (file_id, 0, IDBrtIndexLeaf, &lt_buffer) ;
Packit b099d7
  lt_recptr = (IDBIndexLeafRecordPtr) lt_buffer->IDB_record ;
Packit b099d7
  Idb__INX_CopyLeafRecord (lt_recptr, gt_recptr) ;
Packit b099d7
  Idb__INX_CollapseLeafRecord (lt_recptr, 0, lt_cnt-1) ;
Packit b099d7
  Idb__INX_CollapseLeafRecord (gt_recptr, p_index+1, p_index+gt_cnt) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Both records now have their parent set correctly via the copy operation,
Packit b099d7
   * since our check on space in the parent guarantees that the parent
Packit b099d7
   * pointer present in the original buffer will remain the parent after
Packit b099d7
   * we host the pivot index (unless we create a new root node, which
Packit b099d7
   * is guaranteed safe anyway. So we we can mark the buffers and
Packit b099d7
   * hoist the pivot index.
Packit b099d7
   */
Packit b099d7
  Idb__BM_MarkModified (lt_buffer) ;
Packit b099d7
  Idb__BM_MarkModified (gt_buffer) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Either enter the hoisted entry into the parent, or create
Packit b099d7
   * a parent (which will be the root record).
Packit b099d7
   */
Packit b099d7
  if ( !p_recno )
Packit b099d7
    {
Packit b099d7
      result = Idb__INX_InitRootNodeRecord
Packit b099d7
        (file_id, &p_buffer, p_index_stg, p_data,
Packit b099d7
         _IdbBufferRecordNumber(lt_buffer), _IdbBufferRecordNumber(gt_buffer)) ;
Packit b099d7
      return result ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Hoist the entry into the parent (we know there should be room).
Packit b099d7
   * The parent is already loaded in its buffer as part of the space check.
Packit b099d7
   */
Packit b099d7
  result = Idb__INX_EnterNodeIndex
Packit b099d7
    (file_id, p_buffer, p_index_stg, p_data,
Packit b099d7
     _IdbBufferRecordNumber(lt_buffer), _IdbBufferRecordNumber(gt_buffer)) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Successfully added.
Packit b099d7
   */
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_SplitRecord splits an index record in order to make room
Packit b099d7
 *	for new entries. This is the crucial routine in causing the B-tree
Packit b099d7
 *	to grow. It splits node records only.
Packit b099d7
 *
Packit b099d7
 *	The split process takes place as follows:
Packit b099d7
 *		- extract the middle entry from the record and save it.
Packit b099d7
 *		- create a new node record and move all the less-than
Packit b099d7
 *		  ordered entries into it.
Packit b099d7
 *		- reorganize the current record to contain only the greater-than
Packit b099d7
 *		  ordered entries (garbage collecting the string heap).
Packit b099d7
 *		- Enter the extracted entry in the parent (creating a new
Packit b099d7
 *		  parent if required). This entry takes the less-than
Packit b099d7
 *		  record with it to the parent, thus entering the new node
Packit b099d7
 *		  record in the B-tree. The old record is retained as a
Packit b099d7
 *		  greater-than record for the extracted index.
Packit b099d7
 *
Packit b099d7
 *	For node records, the record vectors are handled entirely by
Packit b099d7
 *	the collapse routines. No record number is saved for the hoisted
Packit b099d7
 *	index, since the associated record number is either new LT record
Packit b099d7
 *	or both records if a root node is created.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	gt_buffer	Buffer containing node index record to be split. This
Packit b099d7
 *			will become the new GT buffer.
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmBAD_RECORD	not a node index record
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal
Packit b099d7
Idb__INX_SplitNodeRecord (IDBFile		file_id,
Packit b099d7
			  IDBRecordBufferPtr	gt_buffer)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordNumber	p_recno ;	/* parent record number */
Packit b099d7
  IDBRecordBufferPtr	p_buffer ;	/* parent buffer */
Packit b099d7
  IDBRecordBufferPtr	lt_buffer ;	/* buffer for LT node record */
Packit b099d7
  IDBIndexNodeRecordPtr	lt_recptr ;	/* LT node record in buffer */
Packit b099d7
  IDBIndexNodeRecordPtr	gt_recptr ;	/* GT node record in buffer */
Packit b099d7
  IDBIndexNodeHdrPtr	gt_hdrptr ;	/* GT record header */
Packit b099d7
  IDBRecordNumber	lt_recno ;	/* LT node record number */
Packit b099d7
  IDBRecordNumber	gt_recno ;	/* GT node record number */
Packit b099d7
  MrmCount		p_index ;	/* index of hoisted entry */
Packit b099d7
  char			p_index_stg[IDBMaxIndexLength1]; /* save hoisted indx */
Packit b099d7
  char			*p_index_stgadr ; /* Address of hoisted index string */
Packit b099d7
  IDBDataHandle		p_data ;	/* saves hoisted entry data */
Packit b099d7
  MrmCount		lt_cnt ;	/* number of LT items */
Packit b099d7
  MrmCount		gt_cnt ;	/* number of GT items */
Packit b099d7
  MrmCount		old_cnt ;	/* original number of items */
Packit b099d7
  IDBIndexNodeEntryPtr	old_itmvec ;	/* Original vector */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize pointers into the record and sanity check. This record
Packit b099d7
   * will become the GT node record
Packit b099d7
   */
Packit b099d7
  if ( ! Idb__INX_ValidNode(gt_buffer) )
Packit b099d7
    return Urm__UT_Error ("Idb__INX_SplitNodeRecord", _MrmMMsg_0010,
Packit b099d7
			  file_id, NULL, MrmBAD_RECORD) ;
Packit b099d7
Packit b099d7
  gt_recptr = (IDBIndexNodeRecordPtr) gt_buffer->IDB_record ;
Packit b099d7
  gt_hdrptr = (IDBIndexNodeHdrPtr) &gt_recptr->node_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * If this node has a parent, make sure it can hold a new entry.
Packit b099d7
   * If not, it will split, and we must retry. Note a parent must be
Packit b099d7
   * a node record.
Packit b099d7
   */
Packit b099d7
  p_recno = gt_hdrptr->parent ;
Packit b099d7
  if ( p_recno )
Packit b099d7
    {
Packit b099d7
      result = Idb__BM_GetRecord (file_id, p_recno, &p_buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      if ( ! Idb__INX_ValidNode(p_buffer) )
Packit b099d7
        return Urm__UT_Error ("Idb__INX_SplitNodeRecord", _MrmMMsg_0018,
Packit b099d7
			      file_id, NULL, MrmBAD_RECORD) ;
Packit b099d7
      result = Idb__INX_ConfirmNodeSpace (file_id, p_buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Pick up current parameters
Packit b099d7
   */
Packit b099d7
  old_cnt = gt_hdrptr->index_count ;
Packit b099d7
  old_itmvec = gt_recptr->index ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Compute the indexes and counts for the split, and save the hoisted entry.
Packit b099d7
   */
Packit b099d7
  lt_cnt = old_cnt / 2 ;
Packit b099d7
  p_index = lt_cnt ;
Packit b099d7
  gt_cnt = old_cnt - lt_cnt - 1;
Packit b099d7
  p_index_stgadr = (char *) old_itmvec+old_itmvec[p_index].index_stg ;
Packit b099d7
  strcpy (p_index_stg, p_index_stgadr) ;
Packit b099d7
  p_data.rec_no = old_itmvec[p_index].data.internal_id.rec_no ;
Packit b099d7
  p_data.item_offs = old_itmvec[p_index].data.internal_id.item_offs ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Acquire a new record to become the LT part. Copy the entire current
Packit b099d7
   * record into it, then collapse both records into their final form.
Packit b099d7
   */
Packit b099d7
  result = Idb__BM_InitRecord (file_id, 0, IDBrtIndexNode, &lt_buffer) ;
Packit b099d7
  lt_recptr = (IDBIndexNodeRecordPtr) lt_buffer->IDB_record ;
Packit b099d7
  Idb__INX_CopyNodeRecord (lt_recptr, gt_recptr) ;
Packit b099d7
  Idb__INX_CollapseNodeRecord (lt_recptr, 0, lt_cnt-1) ;
Packit b099d7
  Idb__INX_CollapseNodeRecord (gt_recptr, p_index+1, p_index+gt_cnt) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Both records now have their parent set correctly via the copy operation,
Packit b099d7
   * since our check on space in the parent guarantees that the parent
Packit b099d7
   * pointer present in the original buffer will remain the parent after
Packit b099d7
   * we host the pivot index (unless we create a new root node, which
Packit b099d7
   * is guaranteed safe anyway. Thus we are done with all changes to these
Packit b099d7
   * buffers, and can mark them. Then save their record numbers and child
Packit b099d7
   * list for future operations.
Packit b099d7
   */
Packit b099d7
  Idb__BM_MarkModified (lt_buffer) ;
Packit b099d7
  Idb__BM_MarkModified (gt_buffer) ;
Packit b099d7
Packit b099d7
  lt_recno = _IdbBufferRecordNumber (lt_buffer) ;
Packit b099d7
  gt_recno = _IdbBufferRecordNumber (gt_buffer) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Either enter the hoisted entry into the parent, or create
Packit b099d7
   * a parent (which will be the root record).
Packit b099d7
   *
Packit b099d7
   * Otherwise, hoist the entry into the parent (we know there should be room).
Packit b099d7
   * The parent should be already loaded in its buffer as part of the space
Packit b099d7
   * check, but a reload is done to make sure buffer turning hasn't interfered.
Packit b099d7
   */
Packit b099d7
  if ( !p_recno )
Packit b099d7
    {
Packit b099d7
      result = Idb__INX_InitRootNodeRecord
Packit b099d7
        (file_id, &p_buffer, p_index_stg, p_data, lt_recno, gt_recno) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
    }
Packit b099d7
  else
Packit b099d7
    {
Packit b099d7
      result = Idb__BM_GetRecord (file_id, p_recno, &p_buffer) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      result = Idb__INX_EnterNodeIndex
Packit b099d7
        (file_id, p_buffer, p_index_stg, p_data, lt_recno, gt_recno) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Now all child nodes of the split record must have their parent
Packit b099d7
   * pointers updated. The gt_buffer children should still have the same
Packit b099d7
   * parent, but the update will be done to that buffer as well for
Packit b099d7
   * completeness.
Packit b099d7
   */
Packit b099d7
  result = Idb__INX_FixNodeChildren (file_id, lt_recno) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
  result = Idb__INX_FixNodeChildren (file_id, gt_recno) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Successfully added.
Packit b099d7
   */
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_InitLeafRecord initializes a new leaf index record,
Packit b099d7
 *	resulting in an empty record with the maximum free space available.
Packit b099d7
 *	It may be immediately used to enter an index item. This routine
Packit b099d7
 *	is used just once, to create the initial root record. Thereafter,
Packit b099d7
 *	all leaf records are created by splitting and collapsing existing
Packit b099d7
 *	records.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	buffer_return	To return pointer to buffer containing new record
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_InitRootLeafRecord (IDBFile		file_id,
Packit b099d7
			     IDBRecordBufferPtr	*buffer_return)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordBufferPtr	bufptr ;	/* leaf record buffer */
Packit b099d7
  IDBIndexLeafRecordPtr	recptr ;	/* leaf record in buffer */
Packit b099d7
  IDBIndexLeafHdrPtr	hdrptr ;	/* record header */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Acquire a record
Packit b099d7
   */
Packit b099d7
  result = Idb__BM_InitRecord (file_id, 0, IDBrtIndexLeaf, &bufptr) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
  recptr = (IDBIndexLeafRecordPtr) bufptr->IDB_record ;
Packit b099d7
  hdrptr = (IDBIndexLeafHdrPtr) &recptr->leaf_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize the record header
Packit b099d7
   */
Packit b099d7
  hdrptr->parent = 0 ;
Packit b099d7
  hdrptr->index_count = 0 ;
Packit b099d7
  hdrptr->heap_start = IDBIndexLeafFreeMax ;
Packit b099d7
  hdrptr->free_bytes = IDBIndexLeafFreeMax ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Successfully initialized
Packit b099d7
   */
Packit b099d7
  Idb__BM_MarkModified (bufptr) ;
Packit b099d7
  *buffer_return = bufptr ;
Packit b099d7
Packit b099d7
  file_id->index_root = hdrptr->header.record_num ;
Packit b099d7
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	Idb__INX_InitNodeRecord initializes a new node index record. It
Packit b099d7
 *	creates the initial entry in the record, with its index, data pointer,
Packit b099d7
 *	and pointers to two children records in the B-tree. This entry always
Packit b099d7
 *	becomes the root of the B-tree, since the only occasion on which
Packit b099d7
 *	a node record is created in this way is when a new root is needed.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	buffer_return	To return pointer to buffer containing new record
Packit b099d7
 *	index		Index for single entry in record
Packit b099d7
 *	data_entry	Data entry pointer for data
Packit b099d7
 *	lt_record	Record number of B-tree record ordering < the index
Packit b099d7
 *	gt_record	Record number of B-tree record ordering > the index
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmFAILURE	some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_InitRootNodeRecord (IDBFile			file_id,
Packit b099d7
			     IDBRecordBufferPtr		*buffer_return,
Packit b099d7
			     char			*index,
Packit b099d7
			     IDBDataHandle		data_entry,
Packit b099d7
			     IDBRecordNumber		lt_record,
Packit b099d7
			     IDBRecordNumber		gt_record)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordBufferPtr	bufptr ;	/* node record buffer */
Packit b099d7
  IDBIndexNodeRecordPtr	recptr ;	/* node record in buffer */
Packit b099d7
  IDBIndexNodeHdrPtr	hdrptr ;	/* record header */
Packit b099d7
  IDBRecordNumber	recno ;		/* this buffer's record number */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Acquire a record
Packit b099d7
   */
Packit b099d7
  result = Idb__BM_InitRecord (file_id, 0, IDBrtIndexNode, &bufptr) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
  recptr = (IDBIndexNodeRecordPtr) bufptr->IDB_record ;
Packit b099d7
  hdrptr = (IDBIndexNodeHdrPtr) &recptr->node_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize the record header
Packit b099d7
   */
Packit b099d7
  hdrptr->parent = 0 ;
Packit b099d7
  hdrptr->index_count = 0 ;
Packit b099d7
  hdrptr->heap_start = IDBIndexNodeFreeMax ;
Packit b099d7
  hdrptr->free_bytes = IDBIndexNodeFreeMax ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Enter the initial entry
Packit b099d7
   */
Packit b099d7
  result = Idb__INX_EnterNodeIndex
Packit b099d7
    (file_id, bufptr, index, data_entry, lt_record, gt_record) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Successfully initialized
Packit b099d7
   */
Packit b099d7
  Idb__BM_MarkModified (bufptr) ;
Packit b099d7
  *buffer_return = bufptr ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Set the parent pointers in the two child entries.
Packit b099d7
   */
Packit b099d7
  recno = _IdbBufferRecordNumber (bufptr) ;
Packit b099d7
  result = Idb__INX_SetParent (file_id, recno, lt_record) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
  result = Idb__INX_SetParent (file_id, recno, gt_record) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Root node successfully created. Update file header.
Packit b099d7
   */
Packit b099d7
  file_id->index_root = hdrptr->header.record_num ;
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routines copies one leaf record into another.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	dst_recptr	pointer to record into which to copy
Packit b099d7
 *	src_recptr	source record pointer
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
void 
Packit b099d7
Idb__INX_CopyLeafRecord (IDBIndexLeafRecordPtr	dst_recptr,
Packit b099d7
			 IDBIndexLeafRecordPtr	src_recptr)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  IDBIndexLeafHdrPtr	dst_hdrptr ;	/* destination record header */
Packit b099d7
  IDBIndexLeafHdrPtr	src_hdrptr ;	/* source record header */
Packit b099d7
  char			*dst_data ;	/* data part of dest record */
Packit b099d7
  char			*src_data ;	/* data part of source record */
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * copy the header, field by field
Packit b099d7
   */
Packit b099d7
  dst_hdrptr = (IDBIndexLeafHdrPtr) &dst_recptr->leaf_header ;
Packit b099d7
  src_hdrptr = (IDBIndexLeafHdrPtr) &src_recptr->leaf_header ;
Packit b099d7
  dst_hdrptr->parent = src_hdrptr->parent ;
Packit b099d7
  dst_hdrptr->index_count = src_hdrptr->index_count ;
Packit b099d7
  dst_hdrptr->heap_start = src_hdrptr->heap_start ;
Packit b099d7
  dst_hdrptr->free_bytes = src_hdrptr->free_bytes ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * copy the data area in the record
Packit b099d7
   */
Packit b099d7
  dst_data = (char *) dst_recptr->index ;
Packit b099d7
  src_data = (char *) src_recptr->index ;
Packit b099d7
Packit b099d7
  UrmBCopy (src_data, dst_data, IDBIndexLeafFreeMax) ;
Packit b099d7
Packit b099d7
}
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routines copies one node record into another.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	dst_recptr	pointer to record into which to copy
Packit b099d7
 *	src_recptr	source record pointer
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
void 
Packit b099d7
Idb__INX_CopyNodeRecord (IDBIndexNodeRecordPtr	dst_recptr,
Packit b099d7
			 IDBIndexNodeRecordPtr	src_recptr)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  IDBIndexNodeHdrPtr	dst_hdrptr ;	/* destination record header */
Packit b099d7
  IDBIndexNodeHdrPtr	src_hdrptr ;	/* source record header */
Packit b099d7
  char			*dst_data ;	/* data part of dest record */
Packit b099d7
  char			*src_data ;	/* data part of source record */
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * copy the header, field by field
Packit b099d7
   */
Packit b099d7
  dst_hdrptr = (IDBIndexNodeHdrPtr) &dst_recptr->node_header ;
Packit b099d7
  src_hdrptr = (IDBIndexNodeHdrPtr) &src_recptr->node_header ;
Packit b099d7
  dst_hdrptr->parent = src_hdrptr->parent ;
Packit b099d7
  dst_hdrptr->index_count = src_hdrptr->index_count ;
Packit b099d7
  dst_hdrptr->heap_start = src_hdrptr->heap_start ;
Packit b099d7
  dst_hdrptr->free_bytes = src_hdrptr->free_bytes ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * copy the data area in the record
Packit b099d7
   */
Packit b099d7
  dst_data = (char *) dst_recptr->index ;
Packit b099d7
  src_data = (char *) src_recptr->index ;
Packit b099d7
  UrmBCopy (src_data, dst_data, IDBIndexNodeFreeMax) ;
Packit b099d7
Packit b099d7
}
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routine collapses a leaf index record as part of splitting
Packit b099d7
 *	a record. Collapsing the record truncates the record contents
Packit b099d7
 *	by removing part of the index vector, re-organizing the string
Packit b099d7
 *	heap to consume minimal space, resetting the heap parameters,
Packit b099d7
 *	and resetting the index count.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	recptr		The leaf index record to collapse
Packit b099d7
 *	start		First entry in the index vector to be preserved
Packit b099d7
 *	end		Last entry in the index vector to be preserved
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
void 
Packit b099d7
Idb__INX_CollapseLeafRecord (IDBIndexLeafRecordPtr	recptr,
Packit b099d7
			     MrmCount			start,
Packit b099d7
			     MrmCount			end)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  IDBIndexLeafHdrPtr	hdrptr ;	/* record header */
Packit b099d7
  int			ndx ;		/* loop index */
Packit b099d7
  char			*temp_heap ;	/* temporary heap */
Packit b099d7
  char			*cur_heap ;	/* current heap pointer */
Packit b099d7
  MrmCount		heap_size ;	/* # bytes used in temp heap */
Packit b099d7
  IDBIndexLeafEntryPtr	srcvec ;	/* source index vector */
Packit b099d7
  IDBIndexLeafEntryPtr	dstvec ;	/* destination index vector */
Packit b099d7
  char			*stgbase ;	/* base address for string offsets */
Packit b099d7
  char			*ndxstg ;	/* current index string */
Packit b099d7
  MrmCount		stgsiz ;	/* # bytes for current string */
Packit b099d7
  MrmCount		ndxcnt ;	/* # entries in collapsed record */
Packit b099d7
  MrmCount		nfree ;		/* # free bytes in collapsed record */
Packit b099d7
  MrmOffset		heap_start ;	/* new heap start offset */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Allocate a temporary heap (big enough to hold data area). Copy each
Packit b099d7
   * string which must be preserved into the temporary heap. The heap
Packit b099d7
   * is allocated top-to-bottom, and the temporary offsets will be
Packit b099d7
   * made permanent when the temporary heap is copied into the record.
Packit b099d7
   *
Packit b099d7
   * Copy the surviving part of the index vector while saving the strings.
Packit b099d7
   * The new offset is set as part of this operation.
Packit b099d7
   */
Packit b099d7
  temp_heap = (char *) XtMalloc (IDBIndexLeafFreeMax) ;
Packit b099d7
  cur_heap = temp_heap ;
Packit b099d7
  heap_size = 0 ;
Packit b099d7
Packit b099d7
  hdrptr = (IDBIndexLeafHdrPtr) &recptr->leaf_header ;
Packit b099d7
  srcvec = &recptr->index[start] ;
Packit b099d7
  dstvec = &recptr->index[0] ;
Packit b099d7
  stgbase = (char *) recptr->index ;
Packit b099d7
  ndxcnt = end - start + 1 ;
Packit b099d7
Packit b099d7
  for ( ndx=0 ; ndx
Packit b099d7
    {
Packit b099d7
      dstvec[ndx].data = srcvec[ndx].data ;
Packit b099d7
      ndxstg = (char *) stgbase + srcvec[ndx].index_stg ;
Packit b099d7
      strcpy (cur_heap, ndxstg) ;
Packit b099d7
      dstvec[ndx].index_stg = (MrmOffset) (cur_heap - temp_heap) ;
Packit b099d7
      stgsiz = strlen(cur_heap) + 1 ;
Packit b099d7
      stgsiz = _FULLWORD(stgsiz);
Packit b099d7
      cur_heap += stgsiz ;
Packit b099d7
      heap_size += stgsiz ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Compute offsets and sizes, and copy heap into record. Then adjust the
Packit b099d7
   * offset to allow for the free space.
Packit b099d7
   */
Packit b099d7
  hdrptr->index_count = ndxcnt ;
Packit b099d7
  heap_start = IDBIndexLeafFreeMax - heap_size ;
Packit b099d7
  hdrptr->heap_start = heap_start ;
Packit b099d7
  nfree = IDBIndexLeafFreeMax - heap_size - ndxcnt*IDBIndexLeafEntrySize ;
Packit b099d7
  hdrptr->free_bytes = nfree ;
Packit b099d7
Packit b099d7
  UrmBCopy (temp_heap, &stgbase[heap_start], heap_size) ;
Packit b099d7
  for ( ndx=0 ; ndx
Packit b099d7
    dstvec[ndx].index_stg += heap_start ;
Packit b099d7
Packit b099d7
  XtFree (temp_heap) ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routine collapses a node index record as part of splitting
Packit b099d7
 *	a record. Collapsing the record truncates the record contents
Packit b099d7
 *	by removing part of the index vector, re-organizing the string
Packit b099d7
 *	heap to consume minimal space, resetting the heap parameters,
Packit b099d7
 *	and resetting the index count.
Packit b099d7
 *
Packit b099d7
 *	The record vector is preserved by moving entires start to end+1.
Packit b099d7
 *	For both records being collapsed, these entries are the correct
Packit b099d7
 *	ones to associate with the collapsed record.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	recptr		The node index record to collapse
Packit b099d7
 *	start		First entry in the index vector to be preserved
Packit b099d7
 *	end		Last entry in the index vector to be preserved
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
void 
Packit b099d7
Idb__INX_CollapseNodeRecord (IDBIndexNodeRecordPtr	recptr,
Packit b099d7
			     MrmCount			start,
Packit b099d7
			     MrmCount			end)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  IDBIndexNodeHdrPtr	hdrptr ;	/* record header */
Packit b099d7
  int			ndx ;		/* loop index */
Packit b099d7
  char			*temp_heap ;	/* temporary heap */
Packit b099d7
  char			*cur_heap ;	/* current heap pointer */
Packit b099d7
  MrmCount		heap_size ;	/* # bytes used in temp heap */
Packit b099d7
  IDBIndexNodeEntryPtr	srcvec ;	/* source index vector */
Packit b099d7
  IDBIndexNodeEntryPtr	dstvec ;	/* destination index vector */
Packit b099d7
  char			*stgbase ;	/* base address for string offsets */
Packit b099d7
  char			*ndxstg ;	/* current index string */
Packit b099d7
  MrmCount		stgsiz ;	/* # bytes for current string */
Packit b099d7
  MrmCount		ndxcnt ;	/* # entries in collapsed record */
Packit b099d7
  MrmCount		nfree ;		/* # free bytes in collapsed record */
Packit b099d7
  MrmOffset		heap_start ;	/* new heap start offset */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Allocate a temporary heap (big enough to hold data area). Copy each
Packit b099d7
   * string which must be preserved into the temporary heap. The heap
Packit b099d7
   * is allocated top-to-bottom, and the temporary offsets will be
Packit b099d7
   * made permanent when the temporary heap is copied into the record.
Packit b099d7
   *
Packit b099d7
   * Copy the surviving part of the index vector while saving the strings.
Packit b099d7
   * The new offset is set as part of this operation.
Packit b099d7
   */
Packit b099d7
  temp_heap = (char *) XtMalloc (IDBIndexNodeFreeMax) ;
Packit b099d7
  cur_heap = temp_heap ;
Packit b099d7
  heap_size = 0 ;
Packit b099d7
Packit b099d7
  hdrptr = (IDBIndexNodeHdrPtr) &recptr->node_header ;
Packit b099d7
  srcvec = &recptr->index[start] ;
Packit b099d7
  dstvec = &recptr->index[0] ;
Packit b099d7
  stgbase = (char *) recptr->index ;
Packit b099d7
  ndxcnt = end - start + 1 ;
Packit b099d7
Packit b099d7
  for ( ndx=0 ; ndx
Packit b099d7
    {
Packit b099d7
      dstvec[ndx].data = srcvec[ndx].data ;
Packit b099d7
      dstvec[ndx].LT_record = srcvec[ndx].LT_record ;
Packit b099d7
      dstvec[ndx].GT_record = srcvec[ndx].GT_record ;
Packit b099d7
      ndxstg = (char *) stgbase + srcvec[ndx].index_stg ;
Packit b099d7
      strcpy (cur_heap, ndxstg) ;
Packit b099d7
      dstvec[ndx].index_stg = (MrmOffset) (cur_heap - temp_heap) ;
Packit b099d7
      stgsiz = strlen(cur_heap) + 1 ;
Packit b099d7
      stgsiz = _FULLWORD(stgsiz);
Packit b099d7
      cur_heap += stgsiz ;
Packit b099d7
      heap_size += stgsiz ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Compute offsets and sizes, and copy heap into record. Then adjust the
Packit b099d7
   * offset to allow for the free space.
Packit b099d7
   */
Packit b099d7
  hdrptr->index_count = ndxcnt ;
Packit b099d7
  heap_start = IDBIndexNodeFreeMax - heap_size ;
Packit b099d7
  hdrptr->heap_start = heap_start ;
Packit b099d7
  nfree = IDBIndexNodeFreeMax - heap_size - ndxcnt*IDBIndexNodeEntrySize ;
Packit b099d7
  hdrptr->free_bytes = nfree ;
Packit b099d7
Packit b099d7
  UrmBCopy (temp_heap, &stgbase[heap_start], heap_size) ;
Packit b099d7
  for ( ndx=0 ; ndx
Packit b099d7
    dstvec[ndx].index_stg += heap_start ;
Packit b099d7
Packit b099d7
  XtFree (temp_heap) ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routine confirms that there is enough space in an index
Packit b099d7
 *	node for a new entry. If there is not, it splits the entry
Packit b099d7
 *	and tells the caller to retry.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	buffer		Buffer containing the node record to be checked.
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	There is enough space
Packit b099d7
 *	MrmINDEX_RETRY	Node was split, caller must retry
Packit b099d7
 *	MrmFAILURE	Some other failure
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_ConfirmNodeSpace (IDBFile		file_id,
Packit b099d7
			   IDBRecordBufferPtr	buffer)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBIndexNodeRecordPtr	recptr ;	/* node record in buffer */
Packit b099d7
  IDBIndexNodeHdrPtr	hdrptr ;	/* record header */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Initialize pointers into the record
Packit b099d7
   */
Packit b099d7
  recptr = (IDBIndexNodeRecordPtr) buffer->IDB_record ;
Packit b099d7
  hdrptr = (IDBIndexNodeHdrPtr) &recptr->node_header ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Check the size. If there is enough, OK. Else split this record and
Packit b099d7
   * return a retry.
Packit b099d7
   */
Packit b099d7
  if ( hdrptr->free_bytes >= IDBIndexNodeEntryMax ) return MrmSUCCESS ;
Packit b099d7
Packit b099d7
  result = Idb__INX_SplitNodeRecord (file_id, buffer) ;
Packit b099d7
  if ( result == MrmSUCCESS ) result = MrmINDEX_RETRY ;
Packit b099d7
Packit b099d7
  return result ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routine sets the parent pointer in a child record
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	parent_record	Parent record number
Packit b099d7
 *	child_record	Child record number
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *	MrmSUCCESS	operation succeeded
Packit b099d7
 *	MrmFAILURE	some failure occurred
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_SetParent (IDBFile		file_id,
Packit b099d7
		    IDBRecordNumber	parent_record,
Packit b099d7
		    IDBRecordNumber	child_record)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordBufferPtr	buffer ;	/* buffer for child record */
Packit b099d7
  IDBIndexLeafRecordPtr	leafrec ;	/* index leaf record */
Packit b099d7
  IDBIndexLeafHdrPtr	leafhdr ;	/* index leaf header */
Packit b099d7
  IDBIndexNodeRecordPtr	noderec ;	/* index node record */
Packit b099d7
  IDBIndexNodeHdrPtr	nodehdr ;	/* index node header */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Get the child record
Packit b099d7
   */
Packit b099d7
  result = Idb__BM_GetRecord (file_id, child_record, &buffer) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
  if ( ! Idb__INX_ValidRecord(buffer) )
Packit b099d7
    return Urm__UT_Error ("Idb__INX_SetParent", _MrmMMsg_0010,
Packit b099d7
			  file_id, NULL, MrmBAD_RECORD) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Set up pointers and set parent based on record type
Packit b099d7
   */
Packit b099d7
  switch ( _IdbBufferRecordType (buffer) )
Packit b099d7
    {
Packit b099d7
    case IDBrtIndexLeaf:
Packit b099d7
      leafrec = (IDBIndexLeafRecordPtr) buffer->IDB_record ;
Packit b099d7
      leafhdr = (IDBIndexLeafHdrPtr) &leafrec->leaf_header ;
Packit b099d7
      if ( leafhdr->parent != parent_record )
Packit b099d7
	{
Packit b099d7
	  leafhdr->parent = parent_record ;
Packit b099d7
	  Idb__BM_MarkModified (buffer) ;
Packit b099d7
	}
Packit b099d7
      return MrmSUCCESS ;
Packit b099d7
    case IDBrtIndexNode:
Packit b099d7
      noderec = (IDBIndexNodeRecordPtr) buffer->IDB_record ;
Packit b099d7
      nodehdr = (IDBIndexNodeHdrPtr) &noderec->node_header ;
Packit b099d7
      if ( nodehdr->parent != parent_record )
Packit b099d7
	{
Packit b099d7
	  nodehdr->parent = parent_record ;
Packit b099d7
	  Idb__BM_MarkModified (buffer) ;
Packit b099d7
	}
Packit b099d7
      return MrmSUCCESS ;
Packit b099d7
    default:
Packit b099d7
      return MrmBAD_RECORD ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7

Packit b099d7
/*
Packit b099d7
 *++
Packit b099d7
 *
Packit b099d7
 *  PROCEDURE DESCRIPTION:
Packit b099d7
 *
Packit b099d7
 *	This routine guarantees that the children of a node record have
Packit b099d7
 *	a correct parent pointer.
Packit b099d7
 *
Packit b099d7
 *  FORMAL PARAMETERS:
Packit b099d7
 *
Packit b099d7
 *	file_id		Open IDB file
Packit b099d7
 *	p_record	Record number of parent record
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT INPUTS:
Packit b099d7
 *
Packit b099d7
 *  IMPLICIT OUTPUTS:
Packit b099d7
 *
Packit b099d7
 *  FUNCTION VALUE:
Packit b099d7
 *
Packit b099d7
 *  SIDE EFFECTS:
Packit b099d7
 *
Packit b099d7
 *	This routine uses MarkActivity to guarantee that the parent
Packit b099d7
 *	record remains in memory.
Packit b099d7
 *
Packit b099d7
 *--
Packit b099d7
 */
Packit b099d7
Packit b099d7
Cardinal 
Packit b099d7
Idb__INX_FixNodeChildren (IDBFile		file_id,
Packit b099d7
			  IDBRecordNumber	p_record)
Packit b099d7
{
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   *  Local variables
Packit b099d7
   */
Packit b099d7
  Cardinal		result ;	/* function results */
Packit b099d7
  IDBRecordBufferPtr	buffer ;	/* parent node buffer */
Packit b099d7
  IDBIndexNodeRecordPtr	recptr ;	/* parent node record in buffer */
Packit b099d7
  IDBIndexNodeHdrPtr	hdrptr ;	/* parent record header */
Packit b099d7
  int			ndx ;		/* loop index */
Packit b099d7
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Get the parent record
Packit b099d7
   */
Packit b099d7
  result = Idb__BM_GetRecord (file_id, p_record, &buffer) ;
Packit b099d7
  if ( result != MrmSUCCESS ) return result ;
Packit b099d7
  if ( ! Idb__INX_ValidNode(buffer) )
Packit b099d7
    return Urm__UT_Error ("Idb__INX_FixNodeChildren", _MrmMMsg_0010,
Packit b099d7
			  file_id, NULL, MrmBAD_RECORD) ;
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Bind pointers into the record, and set each child's parent pointer
Packit b099d7
   */
Packit b099d7
  recptr = (IDBIndexNodeRecordPtr) buffer->IDB_record ;
Packit b099d7
  hdrptr = (IDBIndexNodeHdrPtr) &recptr->node_header ;
Packit b099d7
Packit b099d7
  for ( ndx=0 ; ndx<hdrptr->index_count ; ndx++ )
Packit b099d7
    {
Packit b099d7
      result = Idb__INX_SetParent (file_id, p_record,
Packit b099d7
				   recptr->index[ndx].LT_record) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      result = Idb__INX_SetParent (file_id, p_record,
Packit b099d7
				   recptr->index[ndx].GT_record) ;
Packit b099d7
      if ( result != MrmSUCCESS ) return result ;
Packit b099d7
      Idb__BM_MarkActivity (buffer) ;
Packit b099d7
    }
Packit b099d7
Packit b099d7
  /*
Packit b099d7
   * Successfully modified
Packit b099d7
   */
Packit b099d7
  return MrmSUCCESS ;
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7