int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves)
{
  uint i;
  ulong length, block_length= 0;
  uchar *buff= NULL;
  MYISAM_SHARE* share= info->s;
  uint keys= share->state.header.keys;
  MI_KEYDEF *keyinfo= share->keyinfo;
  my_off_t key_file_length= share->state.state.key_file_length;
  my_off_t pos= share->base.keystart;
  DBUG_ENTER("mi_preload");

  if (!keys || !mi_is_any_key_active(key_map) || key_file_length == pos)
    DBUG_RETURN(0);

  block_length= keyinfo[0].block_length;

  if (ignore_leaves)
  {
    /* Check whether all indexes use the same block size */
    for (i= 1 ; i < keys ; i++)
    {
      if (keyinfo[i].block_length != block_length)
        DBUG_RETURN(my_errno= HA_ERR_NON_UNIQUE_BLOCK_SIZE);
    }
  }
  else
    block_length= share->key_cache->key_cache_block_size;

  length= info->preload_buff_size/block_length * block_length;
  set_if_bigger(length, block_length);

  if (!(buff= (uchar *) my_malloc(length, MYF(MY_WME))))
    DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);

  if (flush_key_blocks(share->key_cache,share->kfile, FLUSH_RELEASE))
    goto err;

  do
  {
    /* Read the next block of index file into the preload buffer */
    if ((my_off_t) length > (key_file_length-pos))
      length= (ulong) (key_file_length-pos);
    if (mysql_file_pread(share->kfile, (uchar*) buff, length, pos,
                         MYF(MY_FAE|MY_FNABP)))
      goto err;

    if (ignore_leaves)
    {
      uchar *end= buff+length;
      do
      {
        if (mi_test_if_nod(buff))
        {
          if (key_cache_insert(share->key_cache,
                               share->kfile, pos, DFLT_INIT_HITS,
                              (uchar*) buff, block_length))
	    goto err;
	}
        pos+= block_length;
      }
      while ((buff+= block_length) != end);
      buff= end-length;
    }
    else
    {
      if (key_cache_insert(share->key_cache,
                           share->kfile, pos, DFLT_INIT_HITS,
                           (uchar*) buff, length))
	goto err;
      pos+= length;
    }
  }
  while (pos != key_file_length);

  my_free(buff);
  DBUG_RETURN(0);

err:
  my_free(buff);
  DBUG_RETURN(my_errno= errno);
}
my_bool _ma_read_cache(MARIA_HA *handler, IO_CACHE *info, uchar *buff,
                       my_off_t pos, size_t length, uint flag)
{
  size_t read_length,in_buff_length;
  my_off_t offset;
  uchar *in_buff_pos;
  DBUG_ENTER("_ma_read_cache");

  if (pos < info->pos_in_file)
  {
    read_length=length;
    if ((my_off_t) read_length > (my_off_t) (info->pos_in_file-pos))
      read_length=(uint) (info->pos_in_file-pos);
    info->seek_not_done=1;
    if (mysql_file_pread(info->file,buff,read_length,pos,MYF(MY_NABP)))
      DBUG_RETURN(1);
    if (!(length-=read_length))
      DBUG_RETURN(0);
    pos+=read_length;
    buff+=read_length;
  }
  if (pos >= info->pos_in_file &&
      (offset= (my_off_t) (pos - info->pos_in_file)) <
      (my_off_t) (info->read_end - info->request_pos))
  {
    in_buff_pos=info->request_pos+(uint) offset;
    in_buff_length= MY_MIN(length,(size_t) (info->read_end-in_buff_pos));
    memcpy(buff,info->request_pos+(uint) offset,(size_t) in_buff_length);
    if (!(length-=in_buff_length))
      DBUG_RETURN(0);
    pos+=in_buff_length;
    buff+=in_buff_length;
  }
  else
    in_buff_length=0;
  if (flag & READING_NEXT)
  {
    if (pos != (info->pos_in_file +
		(uint) (info->read_end - info->request_pos)))
    {
      info->pos_in_file=pos;				/* Force start here */
      info->read_pos=info->read_end=info->request_pos;	/* Everything used */
      info->seek_not_done=1;
    }
    else
      info->read_pos=info->read_end;			/* All block used */
    if (!(*info->read_function)(info,buff,length))
      DBUG_RETURN(0);
    read_length=info->error;
  }
  else
  {
    info->seek_not_done=1;
    if ((read_length=mysql_file_pread(info->file,buff,length,pos,MYF(0))) == length)
      DBUG_RETURN(0);
  }
  if (!(flag & READING_HEADER) || (int) read_length == -1 ||
      read_length+in_buff_length < 3)
  {
    DBUG_PRINT("error",
               ("Error %d reading next-multi-part block (Got %d bytes)",
                my_errno, (int) read_length));
    if (!my_errno || my_errno == HA_ERR_FILE_TOO_SHORT)
    {
      if (!handler->in_check_table)
        _ma_set_fatal_error(handler->s, HA_ERR_WRONG_IN_RECORD);
      else
        my_errno= HA_ERR_WRONG_IN_RECORD;
    }
    DBUG_RETURN(1);
  }
  bzero(buff+read_length,MARIA_BLOCK_INFO_HEADER_LENGTH - in_buff_length -
        read_length);
  DBUG_RETURN(0);
} /* _ma_read_cache */