int mi_close(register MI_INFO *info)
{
  int error=0,flag;
  MYISAM_SHARE *share=info->s;
  DBUG_ENTER("mi_close");
  DBUG_PRINT("enter",("base: 0x%lx  reopen: %u  locks: %u",
		      (long) info, (uint) share->reopen,
                      (uint) share->tot_locks));

  pthread_mutex_lock(&THR_LOCK_myisam);
  if (info->lock_type == F_EXTRA_LCK)
    info->lock_type=F_UNLCK;			/* HA_EXTRA_NO_USER_CHANGE */

  if (share->reopen == 1 && share->kfile >= 0)
    _mi_decrement_open_count(info);

  if (info->lock_type != F_UNLCK)
  {
    if (mi_lock_database(info,F_UNLCK))
      error=my_errno;
  }
  pthread_mutex_lock(&share->intern_lock);

  if (share->options & HA_OPTION_READ_ONLY_DATA)
  {
    share->r_locks--;
    share->tot_locks--;
  }
  if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
  {
    if (end_io_cache(&info->rec_cache))
      error=my_errno;
    info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
  }
  flag= !--share->reopen;
  myisam_open_list=list_delete(myisam_open_list,&info->open_list);
  pthread_mutex_unlock(&share->intern_lock);

  my_free(mi_get_rec_buff_ptr(info, info->rec_buff), MYF(MY_ALLOW_ZERO_PTR));
  if (flag)
  {
    if (share->kfile >= 0 &&
	flush_key_blocks(share->key_cache, share->kfile,
			 share->temporary ? FLUSH_IGNORE_CHANGED :
			 FLUSH_RELEASE))
      error=my_errno;
    if (share->kfile >= 0)
    {
      /*
        If we are crashed, we can safely flush the current state as it will
        not change the crashed state.
        We can NOT write the state in other cases as other threads
        may be using the file at this point
      */
      if (share->mode != O_RDONLY && mi_is_crashed(info))
	mi_state_info_write(share->kfile, &share->state, 1);
      if (my_close(share->kfile,MYF(0)))
        error = my_errno;
    }
#ifdef HAVE_MMAP
    if (share->file_map)
      _mi_unmap_file(info);
#endif
    if (share->decode_trees)
    {
      my_free((uchar*) share->decode_trees,MYF(0));
      my_free((uchar*) share->decode_tables,MYF(0));
    }
#ifdef THREAD
    thr_lock_delete(&share->lock);
    VOID(pthread_mutex_destroy(&share->intern_lock));
    {
      int i,keys;
      keys = share->state.header.keys;
      VOID(rwlock_destroy(&share->mmap_lock));
      for(i=0; i<keys; i++) {
	VOID(rwlock_destroy(&share->key_root_lock[i]));
      }
    }
#endif
    my_free((uchar*) info->s,MYF(0));
  }
  pthread_mutex_unlock(&THR_LOCK_myisam);
  if (info->ftparser_param)
  {
    my_free((uchar*)info->ftparser_param, MYF(0));
    info->ftparser_param= 0;
  }
  if (info->dfile >= 0 && my_close(info->dfile,MYF(0)))
    error = my_errno;

  myisam_log_command(MI_LOG_CLOSE,info,NULL,0,error);
  my_free((uchar*) info,MYF(0));

  if (error)
  {
    DBUG_RETURN(my_errno=error);
  }
  DBUG_RETURN(0);
} /* mi_close */
int mi_close(register MI_INFO *info)
{
  int error=0,flag;
  MYISAM_SHARE *share=info->s;
  DBUG_ENTER("mi_close");
  DBUG_PRINT("enter",("base: 0x%lx  reopen: %u  locks: %u",
		      (long) info, (uint) share->reopen,
                      (uint) share->tot_locks));

  mysql_mutex_lock(&THR_LOCK_myisam);
  if (info->lock_type == F_EXTRA_LCK)
    info->lock_type=F_UNLCK;			/* HA_EXTRA_NO_USER_CHANGE */

  if (info->lock_type != F_UNLCK)
  {
    if (mi_lock_database(info,F_UNLCK))
      error=my_errno;
  }
  mysql_mutex_lock(&share->intern_lock);

  if (share->options & HA_OPTION_READ_ONLY_DATA)
  {
    share->r_locks--;
    share->tot_locks--;
  }
  if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
  {
    if (end_io_cache(&info->rec_cache))
      error=my_errno;
    info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
  }
  flag= !--share->reopen;
  myisam_open_list=list_delete(myisam_open_list,&info->open_list);
  mysql_mutex_unlock(&share->intern_lock);

  my_free(mi_get_rec_buff_ptr(info, info->rec_buff));
  if (flag)
  {
    DBUG_EXECUTE_IF("crash_before_flush_keys",
                    if (share->kfile >= 0) abort(););
    if (share->kfile >= 0 &&
	flush_key_blocks(share->key_cache, share->kfile,
			 share->temporary ? FLUSH_IGNORE_CHANGED :
			 FLUSH_RELEASE))
      error=my_errno;
    if (share->kfile >= 0)
    {
      /*
        If we are crashed, we can safely flush the current state as it will
        not change the crashed state.
        We can NOT write the state in other cases as other threads
        may be using the file at this point
      */
      if (share->mode != O_RDONLY && mi_is_crashed(info))
	mi_state_info_write(share->kfile, &share->state, 1);
      /* Decrement open count must be last I/O on this file. */
      _mi_decrement_open_count(info);
      if (mysql_file_close(share->kfile, MYF(0)))
        error = my_errno;
    }
#ifdef HAVE_MMAP
    if (share->file_map)
      _mi_unmap_file(info);
#endif
    if (share->decode_trees)
    {
      my_free(share->decode_trees);
      my_free(share->decode_tables);
    }
    thr_lock_delete(&share->lock);
    mysql_mutex_destroy(&share->intern_lock);
    {
      int i,keys;
      keys = share->state.header.keys;
      mysql_rwlock_destroy(&share->mmap_lock);
      for(i=0; i<keys; i++) {
        mysql_rwlock_destroy(&share->key_root_lock[i]);
      }
    }
    my_free(info->s);
  }