public boolean insertRecord( long value, int blockID ) throws MiniDB_Exception {
    boolean success = false;                             // return value
    BPlusTreeNode path[] = getPathForValue(value);       // blocks (nodes) from root to leaf

    //System.out.println( "BPlusTree : insertRecord (" + blockID + "*," + value + ")" );

    // flag that tells us when to stop moving up levels
    boolean insertedOnNonFullPage = false;               

    // the next value and blockID to insert
    long nextValueToInsert = value;
    int nextBlockToInsert = blockID;
    int currLevel = path.length - 1; 

    boolean errorEncountered = false;

    do{
      BPlusTreeNode currNode = path[currLevel];

      if( currNode.hasRoomForAnotherRecord() ){
	currNode.addRecord(nextValueToInsert, nextBlockToInsert);
	insertedOnNonFullPage = true;
	success = true;
      }
      else{
	BPlusTreeNode rightNode = currNode.split();

	// add the record to either the original node or the new node
	if( nextValueToInsert >= rightNode.getMinValue() ){
	  rightNode.addRecord(nextValueToInsert, nextBlockToInsert);
	}
	else{
	  currNode.addRecord(nextValueToInsert, nextBlockToInsert);
	}

	//System.out.println( "Left Node " + currNode.recordsToString() );
	//System.out.println( "Right Node " + rightNode.recordsToString() );
	//MiniDB_Util.waitHere( "SPLIT" );

	if( currLevel == 0 ){
	  // the root was split, create a new root by adding a level
	  if( !currNode.isLeafNode() ) System.out.println( this.allTreeValuesToString() );

	  System.out.println( " adding level" );
	  int newBlockID = miniDB.addBlockToDB();
	  MiniDB_Block blk = miniDB.bufMgr.pin_block(newBlockID);
	  //System.out.println( "Root blk = " + newBlockID );
	  //BPlusTreeInternalNode newRoot = new BPlusTreeInternalNode(blk, this, currNode, rightNode);

	  BPlusTreeInternalNode newRoot = new BPlusTreeInternalNode(blk, this, true );
	  newRoot.setBlockID( currNode.getThisBlockID(), 0 );

	  if( currNode.isLeafNode() )  newRoot.setValue( rightNode.getMinValue(), 0 );
	  else newRoot.setValue( BPlusTreeInternalNode.pushedUpValue, 0 );

	  newRoot.setBlockID( rightNode.getThisBlockID(), 1 );
	  newRoot.setCurrNumRecordsOnBlock(1);
    
	  //miniDB.bufMgr.unpin_block(newBlockID);
	  success = true;

	  // make changes locally and in the DB to reflect the change in root
	  headBlock.setRootBlockID(newRoot.getThisBlockID());
	  this.rootNode = newRoot;

	  //System.out.println( newRoot.toString() );
	  //System.out.println( newRoot.summaryToString() );
	  //System.out.println( "Root values:   " + newRoot.recordsToString() );
	  //System.out.println( "Root children: " + newRoot.childBlockIDsToString() );
	  //System.out.println( "^^^^^^^^ new root ^^^^^^^" );
	  //if( !currNode.isLeafNode() )  System.out.println( "^^^^^^^^ ABOVE INTERNAL ^^^^^^^" );
	  //MiniDB_Util.waitHere();	  
	  //System.out.println( miniDB.allDBBlocksToString() );
	  //MiniDB_Util.waitHere();	
	  if( !currNode.isLeafNode() ){
	    //System.out.println( this.allTreeValuesToString() );
	    //MiniDB_Util.waitHere();	 
	  } 
	}
	else{  // push up

	  if( currNode.isLeafNode() ){
	    nextValueToInsert = rightNode.getMinValue();
	    nextBlockToInsert = rightNode.getThisBlockID();
	  }
	  else{
	    nextValueToInsert = BPlusTreeInternalNode.pushedUpValue;
	    nextBlockToInsert = rightNode.getThisBlockID();

	    //System.out.println( "Moving up: (" + nextBlockToInsert + "*," + nextValueToInsert + ")" );
	    //MiniDB_Util.waitHere();	  
	  }
	}

	miniDB.bufMgr.unpin_block( rightNode.getThisBlockID() );
      }

      currLevel--;
    }while(!success);

    // decrement the pin count for all the blocks on the original path
    for (int i=0; i<path.length; i++){
      miniDB.bufMgr.unpin_block( path[i].getThisBlockID() );
    }

    //System.out.println( "After split "  );
    // System.out.println( leafNode.summaryToString() );
    //System.out.println( rightNode.summaryToString() );
    // MiniDB_Constants.waitHere("SPLIT");

    return success;
  }