mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	BitKeeper/etc/logging_ok: auto-union client/sql_string.cc: Auto merged configure.in: Auto merged include/my_global.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/r/create.result: Auto merged mysql-test/r/olap.result: Auto merged mysql-test/r/warnings.result: Auto merged mysql-test/t/create.test: Auto merged mysql-test/t/warnings.test: Auto merged mysys/raid.cc: Auto merged scripts/make_binary_distribution.sh: Auto merged sql/field.cc: Auto merged BitKeeper/deleted/.del-ha_isam.cc~4dce65904db2675e: Auto merged BitKeeper/deleted/.del-ha_isammrg.cc~dc682e4755d77a2e: Auto merged sql/ha_berkeley.cc: Auto merged sql/ha_blackhole.cc: Auto merged sql/ha_heap.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_myisam.cc: Auto merged sql/ha_myisammrg.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/handler.cc: Auto merged sql/item.cc: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_geofunc.cc: Auto merged sql/item_strfunc.cc: Auto merged sql/item_subselect.cc: Auto merged sql/item_sum.cc: Auto merged sql/item_timefunc.cc: Auto merged sql/item_uniq.cc: Auto merged sql/lock.cc: Auto merged sql/log_event.cc: Auto merged sql/mysql_priv.h: Auto merged sql/opt_range.h: Auto merged sql/procedure.cc: Auto merged sql/protocol.cc: Auto merged sql/protocol_cursor.cc: Auto merged sql/set_var.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_analyse.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_error.cc: Auto merged sql/sql_handler.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_map.cc: Auto merged sql/sql_olap.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_string.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_udf.cc: Auto merged sql/examples/ha_archive.cc: Auto merged sql/examples/ha_example.cc: Auto merged sql/examples/ha_tina.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/tztime.cc: Auto merged strings/ctype-win1250ch.c: Auto merged mysql-test/r/func_gconcat.result: merge & ensure that 4.1 and 5.0 source have tests in same order mysql-test/r/innodb.result: merge & ensure that 4.1 and 5.0 source have tests in same order mysql-test/t/func_gconcat.test: merge & ensure that 4.1 and 5.0 source have tests in same order mysql-test/t/innodb.test: merge & ensure that 4.1 and 5.0 source have tests in same order sql/item_func.cc: merge sql/mysqld.cc: merge sql/opt_range.cc: merge sql/sql_parse.cc: merge Give better name to goto labels sql/sql_select.cc: merge
		
			
				
	
	
		
			800 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			800 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* Copyright (C) 2000 MySQL AB
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation; either version 2 of the License, or
 | 
						|
   (at your option) any later version.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | 
						|
 | 
						|
/*
 | 
						|
 
 | 
						|
   RAID support for MySQL. Raid 0 (stiping) only implemented yet.
 | 
						|
 
 | 
						|
   Why RAID? Why it must be in MySQL?
 | 
						|
 
 | 
						|
   This is because then you can:
 | 
						|
   1. Have bigger tables than your OS limit. In time of writing this
 | 
						|
      we are hitting to 2GB limit under linux/ext2
 | 
						|
   2. You can get more speed from IO bottleneck by putting
 | 
						|
      Raid dirs on different physical disks.
 | 
						|
   3. Getting more fault tolerance (not implemented yet)
 | 
						|
 
 | 
						|
   Why not to use RAID:
 | 
						|
 
 | 
						|
   1. You are losing some processor power to calculate things,
 | 
						|
      do more syscalls and interrupts.
 | 
						|
 
 | 
						|
   Functionality is supplied by two classes: RaidFd and RaidName.
 | 
						|
   RaidFd supports funtionality over file descriptors like
 | 
						|
   open/create/write/seek/close. RaidName supports functionality
 | 
						|
   like rename/delete where we have no relations to filedescriptors.
 | 
						|
   RaidName can be prorably unchanged for different Raid levels. RaidFd
 | 
						|
   have to be virtual I think ;).
 | 
						|
   You can speed up some calls in MySQL code by skipping RAID code.
 | 
						|
   For example LOAD DATA INFILE never needs to read RAID-ed files.
 | 
						|
   This can be done adding proper "#undef my_read" or similar undef-s
 | 
						|
   in your code. Check out the raid.h!
 | 
						|
 
 | 
						|
   Some explanation about _seek_vector[]
 | 
						|
   This is seek cache. RAID seeks too much and we cacheing this. We
 | 
						|
   fool it and just storing new position in file to _seek_vector.
 | 
						|
   When there is no seeks to do, we are putting RAID_SEEK_DONE into it.
 | 
						|
   Any other value requires seeking to that position.
 | 
						|
 
 | 
						|
   TODO:
 | 
						|
 
 | 
						|
 
 | 
						|
   -  Implement other fancy things like RAID 1 (mirroring) and RAID 5.
 | 
						|
      Should not to be very complex.
 | 
						|
 
 | 
						|
   -  Optimize big blob writes by resorting write buffers and writing
 | 
						|
      big chunks at once instead of doing many syscalls. - after thinking I
 | 
						|
      found this is useless. This is because same thing one can do with just
 | 
						|
      increasing RAID_CHUNKSIZE. Monty, what do you think? tonu.
 | 
						|
 
 | 
						|
   -  If needed, then implement missing syscalls. One known to miss is stat();
 | 
						|
 
 | 
						|
   -  Make and use a thread safe dynamic_array buffer. The used one
 | 
						|
      will not work if needs to be extended at the same time someone is
 | 
						|
      accessing it.
 | 
						|
 
 | 
						|
 
 | 
						|
   tonu@mysql.com & monty@mysql.com
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef USE_PRAGMA_IMPLEMENTATION 
 | 
						|
#pragma implementation				// gcc: Class implementation
 | 
						|
#endif
 | 
						|
 | 
						|
#include "mysys_priv.h"
 | 
						|
#include <my_dir.h>
 | 
						|
#include <m_string.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
#if defined(USE_RAID) && !defined(MYSQL_CLIENT)
 | 
						|
 | 
						|
#define RAID_SEEK_DONE ~(off_t) 0
 | 
						|
#define RAID_SIZE_UNKNOWN ~(my_off_t) 0
 | 
						|
 | 
						|
DYNAMIC_ARRAY RaidFd::_raid_map;
 | 
						|
 | 
						|
 | 
						|
/* ---------------  C compatibility  ---------------*/
 | 
						|
 | 
						|
extern "C" {
 | 
						|
 | 
						|
  void init_raid(void)
 | 
						|
  {
 | 
						|
  /* Allocate memory for global file to raid map */
 | 
						|
    my_init_dynamic_array(&RaidFd::_raid_map, sizeof(RaidFd*), 4096, 1024);
 | 
						|
  }
 | 
						|
  void end_raid(void)
 | 
						|
  {
 | 
						|
    /* Free memory used by raid */
 | 
						|
    delete_dynamic(&RaidFd::_raid_map);
 | 
						|
  }
 | 
						|
 | 
						|
  bool is_raid(File fd)
 | 
						|
  {
 | 
						|
    return RaidFd::IsRaid(fd);
 | 
						|
  }
 | 
						|
 | 
						|
  File my_raid_create(const char *FileName, int CreateFlags, int access_flags,
 | 
						|
		      uint raid_type, uint raid_chunks, ulong raid_chunksize,
 | 
						|
		      myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_create");
 | 
						|
    DBUG_PRINT("enter",("Filename: %s  CreateFlags: %d  access_flags: %d  MyFlags: %d",
 | 
						|
			FileName, CreateFlags, access_flags, MyFlags));
 | 
						|
    if (raid_type)
 | 
						|
    {
 | 
						|
      RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
 | 
						|
      File res = raid->Create(FileName,CreateFlags,access_flags,MyFlags);
 | 
						|
      if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
 | 
						|
      {
 | 
						|
	delete raid;
 | 
						|
	DBUG_RETURN(-1);
 | 
						|
      }
 | 
						|
      DBUG_RETURN(res);
 | 
						|
    }
 | 
						|
    else
 | 
						|
       DBUG_RETURN(my_create(FileName, CreateFlags, access_flags,  MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  File my_raid_open(const char *FileName, int Flags,
 | 
						|
		    uint raid_type, uint raid_chunks, ulong raid_chunksize,
 | 
						|
		    myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_open");
 | 
						|
    DBUG_PRINT("enter",("Filename: %s  Flags: %d  MyFlags: %d",
 | 
						|
			FileName, Flags, MyFlags));
 | 
						|
    if (raid_type)
 | 
						|
    {
 | 
						|
      RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
 | 
						|
      File res = raid->Open(FileName,Flags,MyFlags);
 | 
						|
      if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
 | 
						|
      {
 | 
						|
	delete raid;
 | 
						|
	DBUG_RETURN(-1);
 | 
						|
      }
 | 
						|
      DBUG_RETURN(res);
 | 
						|
    }
 | 
						|
    else
 | 
						|
      DBUG_RETURN(my_open(FileName, Flags, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  my_off_t my_raid_seek(File fd, my_off_t pos,int whence,myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_seek");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  pos: %lu whence: %d  MyFlags: %d",
 | 
						|
			fd, (ulong) pos, whence, MyFlags));
 | 
						|
 | 
						|
    if (is_raid(fd))
 | 
						|
    {
 | 
						|
      assert(pos != MY_FILEPOS_ERROR);
 | 
						|
 | 
						|
      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
      DBUG_RETURN(raid->Seek(pos,whence,MyFlags));
 | 
						|
    }
 | 
						|
    else
 | 
						|
      DBUG_RETURN(my_seek(fd, pos, whence, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  my_off_t my_raid_tell(File fd,myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_tell");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  MyFlags: %d",
 | 
						|
			fd, MyFlags));
 | 
						|
    if (is_raid(fd))
 | 
						|
    {
 | 
						|
      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
      DBUG_RETURN(raid->Tell(MyFlags));
 | 
						|
    }
 | 
						|
    else
 | 
						|
       DBUG_RETURN(my_tell(fd, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  uint my_raid_write(File fd,const byte *Buffer, uint Count, myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_write");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  Buffer: 0x%lx  Count: %u  MyFlags: %d",
 | 
						|
		      fd, Buffer, Count, MyFlags));
 | 
						|
    if (is_raid(fd))
 | 
						|
    {
 | 
						|
      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
      DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
 | 
						|
    } else
 | 
						|
      DBUG_RETURN(my_write(fd,Buffer,Count,MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  uint my_raid_read(File fd, byte *Buffer, uint Count, myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_read");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  Buffer: 0x%lx  Count: %u  MyFlags: %d",
 | 
						|
		      fd, Buffer, Count, MyFlags));
 | 
						|
    if (is_raid(fd))
 | 
						|
    {
 | 
						|
      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
      DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
 | 
						|
    } else
 | 
						|
      DBUG_RETURN(my_read(fd,Buffer,Count,MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
 | 
						|
		     myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_pread");
 | 
						|
    DBUG_PRINT("enter",
 | 
						|
               ("Fd: %d  Buffer: 0x%lx  Count: %u offset: %u  MyFlags: %d",
 | 
						|
                Filedes, Buffer, Count, offset, MyFlags));
 | 
						|
     if (is_raid(Filedes))
 | 
						|
     {
 | 
						|
       assert(offset != MY_FILEPOS_ERROR);
 | 
						|
 | 
						|
       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
 | 
						|
       /* Returning value isn't important because real seek is done later. */
 | 
						|
       raid->Seek(offset,MY_SEEK_SET,MyFlags);
 | 
						|
       DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
 | 
						|
     }
 | 
						|
     else
 | 
						|
       DBUG_RETURN(my_pread(Filedes, Buffer, Count, offset, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count,
 | 
						|
		      my_off_t offset, myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_pwrite");
 | 
						|
    DBUG_PRINT("enter",
 | 
						|
               ("Fd: %d  Buffer: 0x %lx  Count: %u offset: %u  MyFlags: %d",
 | 
						|
                Filedes, Buffer, Count, offset, MyFlags));
 | 
						|
     if (is_raid(Filedes))
 | 
						|
     {
 | 
						|
       assert(offset != MY_FILEPOS_ERROR);
 | 
						|
 | 
						|
       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
 | 
						|
       /* Returning value isn't important because real seek is done later. */
 | 
						|
       raid->Seek(offset,MY_SEEK_SET,MyFlags);
 | 
						|
       DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
 | 
						|
     }
 | 
						|
     else
 | 
						|
       DBUG_RETURN(my_pwrite(Filedes, Buffer, Count, offset, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  int my_raid_lock(File fd, int locktype, my_off_t start, my_off_t length,
 | 
						|
		   myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_lock");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  start: %u  length: %u  MyFlags: %d",
 | 
						|
		      fd, start, length, MyFlags));
 | 
						|
    if (my_disable_locking)
 | 
						|
      DBUG_RETURN(0);
 | 
						|
    if (is_raid(fd))
 | 
						|
    {
 | 
						|
      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
      DBUG_RETURN(raid->Lock(locktype, start, length, MyFlags));
 | 
						|
    }
 | 
						|
    else
 | 
						|
      DBUG_RETURN(my_lock(fd, locktype, start, length, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  int my_raid_close(File fd, myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_close");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  MyFlags: %d",
 | 
						|
		      fd, MyFlags));
 | 
						|
    if (is_raid(fd))
 | 
						|
    {
 | 
						|
      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
      RaidFd *tmp=0;
 | 
						|
      set_dynamic(&RaidFd::_raid_map,(char*) &tmp,fd);
 | 
						|
      int res = raid->Close(MyFlags);
 | 
						|
      delete raid;
 | 
						|
      DBUG_RETURN(res);
 | 
						|
    }
 | 
						|
    else
 | 
						|
      DBUG_RETURN(my_close(fd, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  int my_raid_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
 | 
						|
  {
 | 
						|
    DBUG_ENTER("my_raid_chsize");
 | 
						|
    DBUG_PRINT("enter",("Fd: %d  newlength: %u  MyFlags: %d",
 | 
						|
		      fd, newlength, MyFlags));
 | 
						|
   if (is_raid(fd))
 | 
						|
   {
 | 
						|
     RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
     DBUG_RETURN(raid->Chsize(fd, newlength, filler, MyFlags));
 | 
						|
   }
 | 
						|
   else
 | 
						|
     DBUG_RETURN(my_chsize(fd, newlength, filler, MyFlags));
 | 
						|
  }
 | 
						|
 | 
						|
  int my_raid_rename(const char *from, const char *to,
 | 
						|
		     uint raid_chunks, myf MyFlags)
 | 
						|
  {
 | 
						|
    char from_tmp[FN_REFLEN];
 | 
						|
    char to_tmp[FN_REFLEN];
 | 
						|
    DBUG_ENTER("my_raid_rename");
 | 
						|
 | 
						|
    uint from_pos = dirname_length(from);
 | 
						|
    uint to_pos   = dirname_length(to);
 | 
						|
    memcpy(from_tmp, from, from_pos);
 | 
						|
    memcpy(to_tmp, to, to_pos);
 | 
						|
    for (uint i = 0 ; i < raid_chunks ; i++ )
 | 
						|
    {
 | 
						|
      sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
 | 
						|
      sprintf(to_tmp+to_pos,"%02x/%s", i, to+ to_pos);
 | 
						|
      /* Convert if not unix */
 | 
						|
      unpack_filename(from_tmp, from_tmp);
 | 
						|
      unpack_filename(to_tmp,to_tmp);
 | 
						|
      if (my_rename(from_tmp, to_tmp, MyFlags))
 | 
						|
	DBUG_RETURN(-1);
 | 
						|
    }
 | 
						|
    DBUG_RETURN(0);
 | 
						|
  }
 | 
						|
 | 
						|
  int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags)
 | 
						|
  {
 | 
						|
    char from_tmp[FN_REFLEN];
 | 
						|
    uint from_pos = dirname_length(from);
 | 
						|
    DBUG_ENTER("my_raid_delete");
 | 
						|
 | 
						|
    if (!raid_chunks)
 | 
						|
      DBUG_RETURN(my_delete(from,MyFlags));
 | 
						|
    for (uint i = 0 ; i < raid_chunks ; i++ )
 | 
						|
    {
 | 
						|
      memcpy(from_tmp, from, from_pos);
 | 
						|
      sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
 | 
						|
      /* Convert if not unix */
 | 
						|
      unpack_filename(from_tmp, from_tmp);
 | 
						|
      if (my_delete(from_tmp, MyFlags))
 | 
						|
	DBUG_RETURN(-1);
 | 
						|
    }
 | 
						|
    DBUG_RETURN(0);
 | 
						|
  }
 | 
						|
 | 
						|
  int my_raid_redel(const char *old_name, const char *new_name,
 | 
						|
		    uint raid_chunks, myf MyFlags)
 | 
						|
  {
 | 
						|
    char new_name_buff[FN_REFLEN], old_name_buff[FN_REFLEN];
 | 
						|
    char *new_end, *old_end;
 | 
						|
    uint i,old_length,new_length;
 | 
						|
    int error=0;
 | 
						|
    DBUG_ENTER("my_raid_redel");
 | 
						|
 | 
						|
    old_end=old_name_buff+dirname_part(old_name_buff,old_name);
 | 
						|
    old_length=dirname_length(old_name);
 | 
						|
    new_end=new_name_buff+dirname_part(new_name_buff,new_name);
 | 
						|
    new_length=dirname_length(new_name);
 | 
						|
    for (i=0 ;	i < raid_chunks ; i++)
 | 
						|
    {
 | 
						|
      MY_STAT status;
 | 
						|
      sprintf(new_end,"%02x",i);
 | 
						|
      if (my_stat(new_name_buff,&status, MYF(0)))
 | 
						|
      {
 | 
						|
	DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
	if (my_mkdir(new_name_buff,0777,MYF(0)))
 | 
						|
	{
 | 
						|
	  DBUG_PRINT("error",("mkdir failed for %02x",i));
 | 
						|
	  DBUG_RETURN(-1);
 | 
						|
	}
 | 
						|
      }
 | 
						|
      strxmov(strend(new_end),"/",new_name+new_length,NullS);
 | 
						|
      sprintf(old_end,"%02x/%s",i, old_name+old_length);
 | 
						|
      if (my_redel(old_name_buff, new_name_buff, MyFlags))
 | 
						|
	error=1;
 | 
						|
    }
 | 
						|
    DBUG_RETURN(error);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int my_raid_fstat(int fd, MY_STAT *stat_area, myf MyFlags )
 | 
						|
{
 | 
						|
  DBUG_ENTER("my_raid_fstat");
 | 
						|
  if (is_raid(fd))
 | 
						|
  {
 | 
						|
    RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
    DBUG_RETURN(raid->Fstat(fd, stat_area, MyFlags));
 | 
						|
  }
 | 
						|
  else
 | 
						|
    DBUG_RETURN(my_fstat(fd, stat_area, MyFlags));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* -------------- RaidFd base class begins ----------------*/
 | 
						|
/*
 | 
						|
  RaidFd - raided file is identified by file descriptor
 | 
						|
  this is useful when we open/write/read/close files
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
bool RaidFd::
 | 
						|
IsRaid(File fd)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::IsRaid");
 | 
						|
  DBUG_RETURN((uint) fd < _raid_map.elements &&
 | 
						|
	      *dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
RaidFd::
 | 
						|
RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize)
 | 
						|
  :_raid_type(raid_type), _raid_chunks(raid_chunks),
 | 
						|
   _raid_chunksize(raid_chunksize), _position(0), _size(RAID_SIZE_UNKNOWN),
 | 
						|
   _fd_vector(0)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::RaidFd");
 | 
						|
  DBUG_PRINT("enter",("RaidFd_type: %u  Disks: %u  Chunksize: %d",
 | 
						|
		   raid_type, raid_chunks, raid_chunksize));
 | 
						|
 | 
						|
  /* TODO: Here we should add checks if the malloc fails */
 | 
						|
  _seek_vector=0;				/* In case of errors */
 | 
						|
  my_multi_malloc(MYF(MY_WME),
 | 
						|
		  &_seek_vector,sizeof(off_t)*_raid_chunks,
 | 
						|
		  &_fd_vector, sizeof(File) *_raid_chunks,
 | 
						|
		  NullS);
 | 
						|
  if (!RaidFd::_raid_map.buffer)
 | 
						|
  {					/* Not initied */
 | 
						|
    pthread_mutex_lock(&THR_LOCK_open);	/* Ensure that no other thread */
 | 
						|
    if (!RaidFd::_raid_map.buffer)	/* has done init in between */
 | 
						|
      init_raid();
 | 
						|
    pthread_mutex_unlock(&THR_LOCK_open);
 | 
						|
  }
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
RaidFd::
 | 
						|
~RaidFd() {
 | 
						|
  DBUG_ENTER("RaidFd::~RaidFd");
 | 
						|
  /* We don't have to free _fd_vector ! */
 | 
						|
  my_free((char*) _seek_vector, MYF(MY_ALLOW_ZERO_PTR));
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
File RaidFd::
 | 
						|
Create(const char *FileName, int CreateFlags, int access_flags, myf MyFlags)
 | 
						|
{
 | 
						|
  char RaidFdFileName[FN_REFLEN];
 | 
						|
  DBUG_ENTER("RaidFd::Create");
 | 
						|
  DBUG_PRINT("enter",
 | 
						|
	     ("FileName: %s  CreateFlags: %d  access_flags: %d  MyFlags: %d",
 | 
						|
	      FileName, CreateFlags, access_flags, MyFlags));
 | 
						|
  char DirName[FN_REFLEN];
 | 
						|
  uint pos = dirname_part(DirName, FileName);
 | 
						|
  MY_STAT status;
 | 
						|
  if (!_seek_vector)
 | 
						|
    DBUG_RETURN(-1);				/* Not enough memory */
 | 
						|
 | 
						|
  uint i = _raid_chunks-1;
 | 
						|
  do
 | 
						|
  {
 | 
						|
    /* Create subdir */
 | 
						|
    (void)sprintf(RaidFdFileName,"%s%02x", DirName,i);
 | 
						|
    unpack_dirname(RaidFdFileName,RaidFdFileName);   /* Convert if not unix */
 | 
						|
    if (my_stat(RaidFdFileName,&status, MYF(0)))
 | 
						|
    {
 | 
						|
      DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      if (my_mkdir(RaidFdFileName,0777,MYF(0)))
 | 
						|
      {
 | 
						|
	DBUG_PRINT("error",("mkdir failed for %d",i));
 | 
						|
	goto error;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    /* Create file */
 | 
						|
    sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
 | 
						|
    unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
 | 
						|
    _fd = my_create(RaidFdFileName, CreateFlags ,access_flags, (myf)MyFlags);
 | 
						|
    if (_fd < 0)
 | 
						|
      goto error;
 | 
						|
    _fd_vector[i]=_fd;
 | 
						|
    _seek_vector[i]=RAID_SEEK_DONE;
 | 
						|
  } while (i--);
 | 
						|
  _size=0;
 | 
						|
  DBUG_RETURN(_fd);			/* Last filenr is pointer to map */
 | 
						|
 | 
						|
error:
 | 
						|
  {
 | 
						|
    int save_errno=my_errno;
 | 
						|
    while (++i < _raid_chunks)
 | 
						|
    {
 | 
						|
      my_close(_fd_vector[i],MYF(0));
 | 
						|
      sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
 | 
						|
      unpack_filename(RaidFdFileName,RaidFdFileName);
 | 
						|
      my_delete(RaidFdFileName,MYF(0));
 | 
						|
    }
 | 
						|
    my_errno=save_errno;
 | 
						|
  }
 | 
						|
  DBUG_RETURN(-1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
File RaidFd::
 | 
						|
Open(const char *FileName, int Flags, myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Open");
 | 
						|
  DBUG_PRINT("enter",("FileName: %s  Flags: %d  MyFlags: %d",
 | 
						|
		   FileName, Flags, MyFlags));
 | 
						|
  char DirName[FN_REFLEN];
 | 
						|
  uint pos = dirname_part(DirName, FileName);
 | 
						|
  if (!_seek_vector)
 | 
						|
    DBUG_RETURN(-1);				/* Not enough memory */
 | 
						|
 | 
						|
  for( uint i = 0 ;  i < _raid_chunks ; i++ )
 | 
						|
  {
 | 
						|
    char RaidFdFileName[FN_REFLEN];
 | 
						|
    sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
 | 
						|
    unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
 | 
						|
    _fd = my_open(RaidFdFileName, Flags, MyFlags);
 | 
						|
    if (_fd < 0)
 | 
						|
    {
 | 
						|
      int save_errno=my_errno;
 | 
						|
      while (i-- != 0)
 | 
						|
	my_close(_fd_vector[i],MYF(0));
 | 
						|
      my_errno=save_errno;
 | 
						|
      DBUG_RETURN(_fd);
 | 
						|
    }
 | 
						|
    _fd_vector[i]=_fd;
 | 
						|
    _seek_vector[i]=RAID_SEEK_DONE;
 | 
						|
  }
 | 
						|
  Seek(0L,MY_SEEK_END,MYF(0)); // Trick. We just need to know, how big the file is
 | 
						|
  DBUG_PRINT("info",("MYD file logical size: %llu", _size));
 | 
						|
  DBUG_RETURN(_fd);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int RaidFd::
 | 
						|
Write(const byte *Buffer, uint Count, myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Write");
 | 
						|
  DBUG_PRINT("enter",("Count: %d  MyFlags: %d",
 | 
						|
		      Count, MyFlags));
 | 
						|
  const byte *bufptr = Buffer;
 | 
						|
  uint res=0, GotBytes, ReadNowCount;
 | 
						|
 | 
						|
  // Loop until data is written
 | 
						|
  do {
 | 
						|
    Calculate();
 | 
						|
     // Do seeks when neccessary
 | 
						|
    if (_seek_vector[_this_block] != RAID_SEEK_DONE)
 | 
						|
    {
 | 
						|
      if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
 | 
						|
		  MY_SEEK_SET,
 | 
						|
		  MyFlags) == MY_FILEPOS_ERROR)
 | 
						|
	DBUG_RETURN(-1);
 | 
						|
      _seek_vector[_this_block]=RAID_SEEK_DONE;
 | 
						|
    }
 | 
						|
    ReadNowCount = min(Count, _remaining_bytes);
 | 
						|
    GotBytes = my_write(_fd_vector[_this_block], bufptr, ReadNowCount,
 | 
						|
			MyFlags);
 | 
						|
    DBUG_PRINT("loop",("Wrote bytes: %d", GotBytes));
 | 
						|
    if (GotBytes == MY_FILE_ERROR)
 | 
						|
      DBUG_RETURN(-1);
 | 
						|
    res+= GotBytes;
 | 
						|
    if (MyFlags & (MY_NABP | MY_FNABP))
 | 
						|
      GotBytes=ReadNowCount;
 | 
						|
    bufptr += GotBytes;
 | 
						|
    Count  -= GotBytes;
 | 
						|
    _position += GotBytes;
 | 
						|
  } while(Count);
 | 
						|
  set_if_bigger(_size,_position);
 | 
						|
  DBUG_RETURN(res);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int RaidFd::
 | 
						|
Read(const byte *Buffer, uint Count, myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Read");
 | 
						|
  DBUG_PRINT("enter",("Count: %d  MyFlags: %d",
 | 
						|
		      Count, MyFlags));
 | 
						|
  byte *bufptr = (byte *)Buffer;
 | 
						|
  uint res= 0, GotBytes, ReadNowCount;
 | 
						|
 | 
						|
  // Loop until all data is read (Note that Count may be 0)
 | 
						|
  while (Count)
 | 
						|
  {
 | 
						|
    Calculate();
 | 
						|
    // Do seek when neccessary
 | 
						|
    if (_seek_vector[_this_block] != RAID_SEEK_DONE)
 | 
						|
    {
 | 
						|
      if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
 | 
						|
		  MY_SEEK_SET,
 | 
						|
		  MyFlags) == MY_FILEPOS_ERROR)
 | 
						|
	DBUG_RETURN(-1);
 | 
						|
      _seek_vector[_this_block]=RAID_SEEK_DONE;
 | 
						|
    }
 | 
						|
    // and read
 | 
						|
    ReadNowCount = min(Count, _remaining_bytes);
 | 
						|
    GotBytes = my_read(_fd_vector[_this_block], bufptr, ReadNowCount,
 | 
						|
		       MyFlags & ~(MY_NABP | MY_FNABP));
 | 
						|
    DBUG_PRINT("loop",("Got bytes: %u", GotBytes));
 | 
						|
    if (GotBytes == MY_FILE_ERROR)
 | 
						|
      DBUG_RETURN(-1);
 | 
						|
    if (!GotBytes)				// End of file.
 | 
						|
    {
 | 
						|
      DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? -1 : (int) res);
 | 
						|
    }
 | 
						|
    res+= GotBytes;
 | 
						|
    bufptr += GotBytes;
 | 
						|
    Count  -= GotBytes;
 | 
						|
    _position += GotBytes;
 | 
						|
  }
 | 
						|
  DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? 0 : res);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int RaidFd::
 | 
						|
Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Lock");
 | 
						|
  DBUG_PRINT("enter",("locktype: %d  start: %lu  length: %lu  MyFlags: %d",
 | 
						|
		      locktype, start, length, MyFlags));
 | 
						|
  my_off_t bufptr = start;
 | 
						|
  // Loop until all data is locked
 | 
						|
  while(length)
 | 
						|
  {
 | 
						|
    Calculate();
 | 
						|
    for (uint i = _this_block ; (i < _raid_chunks) && length ; i++ )
 | 
						|
    {
 | 
						|
       uint ReadNowCount = min(length, _remaining_bytes);
 | 
						|
       uint GotBytes = my_lock(_fd_vector[i], locktype, bufptr, ReadNowCount,
 | 
						|
			MyFlags);
 | 
						|
       if ((int) GotBytes == -1)
 | 
						|
	 DBUG_RETURN(-1);
 | 
						|
       bufptr += ReadNowCount;
 | 
						|
       length  -= ReadNowCount;
 | 
						|
       Calculate();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int RaidFd::
 | 
						|
Close(myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Close");
 | 
						|
  DBUG_PRINT("enter",("MyFlags: %d",
 | 
						|
		   MyFlags));
 | 
						|
  for (uint i = 0 ; i < _raid_chunks ; ++i )
 | 
						|
  {
 | 
						|
    int err = my_close(_fd_vector[i], MyFlags);
 | 
						|
    if (err != 0)
 | 
						|
      DBUG_RETURN(err);
 | 
						|
  }
 | 
						|
  /* _fd_vector is erased when RaidFd is released */
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
my_off_t RaidFd::
 | 
						|
Seek(my_off_t pos,int whence,myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Seek");
 | 
						|
  DBUG_PRINT("enter",("Pos: %lu  Whence: %d  MyFlags: %d",
 | 
						|
		   (ulong) pos, whence, MyFlags));
 | 
						|
  switch (whence) {
 | 
						|
  case MY_SEEK_CUR:
 | 
						|
    // FIXME: This is wrong, what is going on there
 | 
						|
    // Just I am relied on fact that MySQL 3.23.7 never uses MY_SEEK_CUR
 | 
						|
    // for anything else except things like ltell()
 | 
						|
    break;
 | 
						|
  case MY_SEEK_SET:
 | 
						|
    if ( _position != pos) // we can be already in right place
 | 
						|
    {
 | 
						|
      uint i;
 | 
						|
      off_t _rounds;
 | 
						|
      _position = pos;
 | 
						|
      Calculate();
 | 
						|
      _rounds = _total_block / _raid_chunks;	    // INT() assumed
 | 
						|
      _rounds*= _raid_chunksize;
 | 
						|
      for (i = 0; i < _raid_chunks ; i++ )
 | 
						|
	if ( i < _this_block )
 | 
						|
	  _seek_vector[i] = _rounds + _raid_chunksize;
 | 
						|
	else if ( i == _this_block )
 | 
						|
	  _seek_vector[i] = _rounds + _raid_chunksize -_remaining_bytes;
 | 
						|
	else					// if ( i > _this_block )
 | 
						|
	  _seek_vector[i] = _rounds;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case MY_SEEK_END:
 | 
						|
    if (_size==RAID_SIZE_UNKNOWN) // We don't know table size yet
 | 
						|
    {
 | 
						|
      uint i;
 | 
						|
      _position = 0;
 | 
						|
      for (i = 0; i < _raid_chunks ; i++ )
 | 
						|
      {
 | 
						|
	my_off_t newpos = my_seek(_fd_vector[i], 0L, MY_SEEK_END, MyFlags);
 | 
						|
	if (newpos == MY_FILEPOS_ERROR)
 | 
						|
	  DBUG_RETURN (MY_FILEPOS_ERROR);
 | 
						|
	_seek_vector[i]=RAID_SEEK_DONE;
 | 
						|
	_position += newpos;
 | 
						|
      }
 | 
						|
      _size=_position;
 | 
						|
    }
 | 
						|
    else if (_position != _size) // Aren't we also already in the end?
 | 
						|
    {
 | 
						|
      uint i;
 | 
						|
      off_t _rounds;
 | 
						|
      _position = _size;
 | 
						|
      Calculate();
 | 
						|
      _rounds = _total_block / _raid_chunks;	    // INT() assumed
 | 
						|
      _rounds*= _raid_chunksize;
 | 
						|
      for (i = 0; i < _raid_chunks ; i++ )
 | 
						|
	if ( i < _this_block )
 | 
						|
	  _seek_vector[i] = _rounds + _raid_chunksize;
 | 
						|
	else if ( i == _this_block )
 | 
						|
	  _seek_vector[i] = _rounds + _raid_chunksize - _remaining_bytes;
 | 
						|
	else					// if ( i > _this_block )
 | 
						|
	  _seek_vector[i] = _rounds;
 | 
						|
      _position=_size;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DBUG_RETURN(_position);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
my_off_t RaidFd::
 | 
						|
Tell(myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Tell");
 | 
						|
  DBUG_PRINT("enter",("MyFlags: %d _position %d",
 | 
						|
		   MyFlags,_position));
 | 
						|
  DBUG_RETURN(_position);
 | 
						|
}
 | 
						|
 | 
						|
int RaidFd::
 | 
						|
Chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Chsize");
 | 
						|
  DBUG_PRINT("enter",("Fd: %d, newlength: %d, MyFlags: %d",
 | 
						|
		   fd, newlength,MyFlags));
 | 
						|
  _position = newlength;
 | 
						|
  Calculate();
 | 
						|
  uint _rounds = _total_block / _raid_chunks;	     // INT() assumed
 | 
						|
  for (uint i = 0; i < _raid_chunks ; i++ )
 | 
						|
  {
 | 
						|
    int newpos;
 | 
						|
    if ( i < _this_block )
 | 
						|
      newpos = my_chsize(_fd_vector[i],
 | 
						|
			 _this_block * _raid_chunksize + (_rounds + 1) *
 | 
						|
			 _raid_chunksize, filler, MyFlags);
 | 
						|
    else if ( i == _this_block )
 | 
						|
      newpos = my_chsize(_fd_vector[i],
 | 
						|
			 _this_block * _raid_chunksize + _rounds *
 | 
						|
			 _raid_chunksize + (newlength % _raid_chunksize),
 | 
						|
			 filler, MyFlags);
 | 
						|
    else // this means: i > _this_block
 | 
						|
      newpos = my_chsize(_fd_vector[i],
 | 
						|
			 _this_block * _raid_chunksize + _rounds *
 | 
						|
			 _raid_chunksize, filler, MyFlags);
 | 
						|
    if (newpos)
 | 
						|
      DBUG_RETURN(1);
 | 
						|
  }
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int RaidFd::
 | 
						|
Fstat(int fd, MY_STAT *stat_area, myf MyFlags )
 | 
						|
{
 | 
						|
  DBUG_ENTER("RaidFd::Fstat");
 | 
						|
  DBUG_PRINT("enter",("fd: %d MyFlags: %d",fd,MyFlags));
 | 
						|
  uint i;
 | 
						|
  int error=0;
 | 
						|
  MY_STAT status;
 | 
						|
  stat_area->st_size=0;
 | 
						|
  stat_area->st_mtime=0;
 | 
						|
  stat_area->st_atime=0;
 | 
						|
  stat_area->st_ctime=0;
 | 
						|
 | 
						|
  for(i=0 ; i < _raid_chunks ; i++)
 | 
						|
  {
 | 
						|
    if (my_fstat(_fd_vector[i],&status,MyFlags))
 | 
						|
      error=1;
 | 
						|
    stat_area->st_size+=status.st_size;
 | 
						|
    set_if_bigger(stat_area->st_mtime,status.st_mtime);
 | 
						|
    set_if_bigger(stat_area->st_atime,status.st_atime);
 | 
						|
    set_if_bigger(stat_area->st_ctime,status.st_ctime);
 | 
						|
  }
 | 
						|
  DBUG_RETURN(error);
 | 
						|
}
 | 
						|
 | 
						|
#endif /* defined(USE_RAID) && !defined(MYSQL_CLIENT) */
 |