raid.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:23k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This library is free software; you can redistribute it and/or
  4.    modify it under the terms of the GNU Library General Public
  5.    License as published by the Free Software Foundation; either
  6.    version 2 of the License, or (at your option) any later version.
  7.    
  8.    This library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.    Library General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU Library General Public
  14.    License along with this library; if not, write to the Free
  15.    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  16.    MA 02111-1307, USA */
  17. /* --------------------------------------------------------*
  18. *
  19. *  RAID support for MySQL. Raid 0 (stiping) only implemented yet.
  20. *
  21. *  Why RAID? Why it must be in MySQL?
  22. *
  23. *  This is because then you can:
  24. *  1. Have bigger tables than your OS limit. In time of writing this
  25. *     we are hitting to 2GB limit under linux/ext2
  26. *  2. You can get more speed from IO bottleneck by putting
  27. *     Raid dirs on different physical disks.
  28. *  3. Getting more fault tolerance (not implemented yet)
  29. *
  30. *  Why not to use RAID:
  31. *
  32. *  1. You are losing some processor power to calculate things,
  33. *     do more syscalls and interrupts.
  34. *
  35. *  Functionality is supplied by two classes: RaidFd and RaidName.
  36. *  RaidFd supports funtionality over file descriptors like
  37. *  open/create/write/seek/close. RaidName supports functionality
  38. *  like rename/delete where we have no relations to filedescriptors.
  39. *  RaidName can be prorably unchanged for different Raid levels. RaidFd
  40. *  have to be virtual I think ;).
  41. *  You can speed up some calls in MySQL code by skipping RAID code.
  42. *  For example LOAD DATA INFILE never needs to read RAID-ed files.
  43. *  This can be done adding proper "#undef my_read" or similar undef-s
  44. *  in your code. Check out the raid.h!
  45. *
  46. *  Some explanation about _seek_vector[]
  47. *  This is seek cache. RAID seeks too much and we cacheing this. We
  48. *  fool it and just storing new position in file to _seek_vector.
  49. *  When there is no seeks to do, we are putting RAID_SEEK_DONE into it.
  50. *  Any other value requires seeking to that position.
  51. *
  52. *  TODO:
  53. *
  54. *
  55. *  -  Implement other fancy things like RAID 1 (mirroring) and RAID 5.
  56. *     Should not to be very complex.
  57. *
  58. *  -  Optimize big blob writes by resorting write buffers and writing
  59. *     big chunks at once instead of doing many syscalls. - after thinking I
  60. *     found this is useless. This is because same thing one can do with just
  61. *     increasing RAID_CHUNKSIZE. Monty, what do you think? tonu.
  62. *
  63. *  -  If needed, then implement missing syscalls. One known to miss is stat();
  64. *
  65. *  -  Make and use a thread safe dynamic_array buffer. The used one
  66. *     will not work if needs to be extended at the same time someone is
  67. *     accessing it.
  68. *
  69. *
  70. *  tonu@mysql.com & monty@mysql.com
  71. * --------------------------------------------------------*/
  72. #ifdef __GNUC__
  73. #pragma implementation // gcc: Class implementation
  74. #endif
  75. #include "mysys_priv.h"
  76. #include "my_dir.h"
  77. #include <m_string.h>
  78. #include <assert.h>
  79. const char *raid_type_string[]={"none","striped"};
  80. extern "C" {
  81.   const char *my_raid_type(int raid_type)
  82.   {
  83.     return raid_type_string[raid_type];
  84.   }
  85. }
  86. #if defined(USE_RAID) && !defined(MYSQL_CLIENT)
  87. #define RAID_SEEK_DONE ~(off_t) 0
  88. #define RAID_SIZE_UNKNOWN ~(my_off_t) 0
  89. DYNAMIC_ARRAY RaidFd::_raid_map;
  90. /* ---------------  C compatibility  ---------------*/
  91. extern "C" {
  92.   void init_raid(void)
  93.   {
  94.   /* Allocate memory for global file to raid map */
  95.     init_dynamic_array(&RaidFd::_raid_map, sizeof(RaidFd*), 4096, 1024);
  96.   }
  97.   void end_raid(void)
  98.   {
  99.     /* Free memory used by raid */
  100.     delete_dynamic(&RaidFd::_raid_map);
  101.   }
  102.   bool is_raid(File fd)
  103.   {
  104.     return RaidFd::IsRaid(fd);
  105.   }
  106.   File my_raid_create(const char *FileName, int CreateFlags, int access_flags,
  107.       uint raid_type, uint raid_chunks, ulong raid_chunksize,
  108.       myf MyFlags)
  109.   {
  110.     DBUG_ENTER("my_raid_create");
  111.     DBUG_PRINT("enter",("Filename: %s  CreateFlags: %d  access_flags: %d  MyFlags: %d",
  112. FileName, CreateFlags, access_flags, MyFlags));
  113.     if (raid_type)
  114.     {
  115.       RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
  116.       File res = raid->Create(FileName,CreateFlags,access_flags,MyFlags);
  117.       if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
  118.       {
  119. delete raid;
  120. DBUG_RETURN(-1);
  121.       }
  122.       DBUG_RETURN(res);
  123.     }
  124.     else
  125.        DBUG_RETURN(my_create(FileName, CreateFlags, access_flags,  MyFlags));
  126.   }
  127.   File my_raid_open(const char *FileName, int Flags,
  128.     uint raid_type, uint raid_chunks, ulong raid_chunksize,
  129.     myf MyFlags)
  130.   {
  131.     DBUG_ENTER("my_raid_open");
  132.     DBUG_PRINT("enter",("Filename: %s  Flags: %d  MyFlags: %d",
  133. FileName, Flags, MyFlags));
  134.     if (raid_type)
  135.     {
  136.       RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
  137.       File res = raid->Open(FileName,Flags,MyFlags);
  138.       if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
  139.       {
  140. delete raid;
  141. DBUG_RETURN(-1);
  142.       }
  143.       DBUG_RETURN(res);
  144.     }
  145.     else
  146.       DBUG_RETURN(my_open(FileName, Flags, MyFlags));
  147.   }
  148.   my_off_t my_raid_seek(File fd, my_off_t pos,int whence,myf MyFlags)
  149.   {
  150.     DBUG_ENTER("my_raid_seek");
  151.     DBUG_PRINT("enter",("Fd: %d  pos: %lu whence: %d  MyFlags: %d",
  152. fd, (ulong) pos, whence, MyFlags));
  153.     assert(pos != MY_FILEPOS_ERROR);
  154.     if (is_raid(fd))
  155.     {
  156.       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  157.       DBUG_RETURN(raid->Seek(pos,whence,MyFlags));
  158.     }
  159.     else
  160.       DBUG_RETURN(my_seek(fd, pos, whence, MyFlags));
  161.   }
  162.   my_off_t my_raid_tell(File fd,myf MyFlags)
  163.   {
  164.     DBUG_ENTER("my_raid_tell");
  165.     DBUG_PRINT("enter",("Fd: %d  MyFlags: %d",
  166. fd, MyFlags));
  167.     if (is_raid(fd))
  168.     {
  169.       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  170.       DBUG_RETURN(raid->Tell(MyFlags));
  171.     }
  172.     else
  173.        DBUG_RETURN(my_tell(fd, MyFlags));
  174.   }
  175.   uint my_raid_write(File fd,const byte *Buffer, uint Count, myf MyFlags)
  176.   {
  177.     DBUG_ENTER("my_raid_write");
  178.     DBUG_PRINT("enter",("Fd: %d  Buffer: %lx  Count: %u  MyFlags: %d",
  179.       fd, Buffer, Count, MyFlags));
  180.     if (is_raid(fd))
  181.     {
  182.       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  183.       DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
  184.     } else
  185.       DBUG_RETURN(my_write(fd,Buffer,Count,MyFlags));
  186.   }
  187.   uint my_raid_read(File fd, byte *Buffer, uint Count, myf MyFlags)
  188.   {
  189.     DBUG_ENTER("my_raid_read");
  190.     DBUG_PRINT("enter",("Fd: %d  Buffer: %lx  Count: %u  MyFlags: %d",
  191.       fd, Buffer, Count, MyFlags));
  192.     if (is_raid(fd))
  193.     {
  194.       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  195.       DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
  196.     } else
  197.       DBUG_RETURN(my_read(fd,Buffer,Count,MyFlags));
  198.   }
  199.   uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
  200.      myf MyFlags)
  201.   {
  202.     DBUG_ENTER("my_raid_pread");
  203.     DBUG_PRINT("enter",("Fd: %d  Buffer: %lx  Count: %u offset: %u  MyFlags: %d",
  204.       Filedes, Buffer, Count, offset, MyFlags));
  205.      if (is_raid(Filedes))
  206.      {
  207.        assert(offset != MY_FILEPOS_ERROR);
  208.        RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
  209.        /* Returning value isn't important because real seek is done later. */
  210.        raid->Seek(offset,MY_SEEK_SET,MyFlags);
  211.        DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
  212.      }
  213.      else
  214.        DBUG_RETURN(my_pread(Filedes, Buffer, Count, offset, MyFlags));
  215.   }
  216.   uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count,
  217.       my_off_t offset, myf MyFlags)
  218.   {
  219.     DBUG_ENTER("my_raid_pwrite");
  220.     DBUG_PRINT("enter",("Fd: %d  Buffer: %lx  Count: %u offset: %u  MyFlags: %d",
  221.       Filedes, Buffer, Count, offset, MyFlags));
  222.      if (is_raid(Filedes))
  223.      {
  224.        assert(offset != MY_FILEPOS_ERROR);
  225.        RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
  226.        /* Returning value isn't important because real seek is done later. */
  227.        raid->Seek(offset,MY_SEEK_SET,MyFlags);
  228.        DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
  229.      }
  230.      else
  231.        DBUG_RETURN(my_pwrite(Filedes, Buffer, Count, offset, MyFlags));
  232.   }
  233.   int my_raid_lock(File fd, int locktype, my_off_t start, my_off_t length,
  234.    myf MyFlags)
  235.   {
  236.     DBUG_ENTER("my_raid_lock");
  237.     DBUG_PRINT("enter",("Fd: %d  start: %u  length: %u  MyFlags: %d",
  238.       fd, start, length, MyFlags));
  239.     if (my_disable_locking)
  240.       DBUG_RETURN(0);
  241.     if (is_raid(fd))
  242.     {
  243.       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  244.       DBUG_RETURN(raid->Lock(locktype, start, length, MyFlags));
  245.     }
  246.     else
  247.       DBUG_RETURN(my_lock(fd, locktype, start, length, MyFlags));
  248.   }
  249.   int my_raid_close(File fd, myf MyFlags)
  250.   {
  251.     DBUG_ENTER("my_raid_close");
  252.     DBUG_PRINT("enter",("Fd: %d  MyFlags: %d",
  253.       fd, MyFlags));
  254.     if (is_raid(fd))
  255.     {
  256.       RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  257.       RaidFd *tmp=0;
  258.       set_dynamic(&RaidFd::_raid_map,(char*) &tmp,fd);
  259.       int res = raid->Close(MyFlags);
  260.       delete raid;
  261.       DBUG_RETURN(res);
  262.     }
  263.     else
  264.       DBUG_RETURN(my_close(fd, MyFlags));
  265.   }
  266.   int my_raid_chsize(File fd, my_off_t newlength, myf MyFlags)
  267.   {
  268.     DBUG_ENTER("my_raid_chsize");
  269.     DBUG_PRINT("enter",("Fd: %d  newlength: %u  MyFlags: %d",
  270.       fd, newlength, MyFlags));
  271.    if (is_raid(fd))
  272.    {
  273.      RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  274.      DBUG_RETURN(raid->Chsize(fd, newlength, MyFlags));
  275.    }
  276.    else
  277.      DBUG_RETURN(my_chsize(fd, newlength, MyFlags));
  278.   }
  279.   int my_raid_rename(const char *from, const char *to,
  280.      uint raid_chunks, myf MyFlags)
  281.   {
  282.     char from_tmp[FN_REFLEN];
  283.     char to_tmp[FN_REFLEN];
  284.     DBUG_ENTER("my_raid_rename");
  285.     uint from_pos = dirname_length(from);
  286.     uint to_pos   = dirname_length(to);
  287.     memcpy(from_tmp, from, from_pos);
  288.     memcpy(to_tmp, to, to_pos);
  289.     for (uint i = 0 ; i < raid_chunks ; i++ )
  290.     {
  291.       sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
  292.       sprintf(to_tmp+to_pos,"%02x/%s", i, to+ to_pos);
  293.       /* Convert if not unix */
  294.       unpack_filename(from_tmp, from_tmp);
  295.       unpack_filename(to_tmp,to_tmp);
  296.       if (my_rename(from_tmp, to_tmp, MyFlags))
  297. DBUG_RETURN(-1);
  298.     }
  299.     DBUG_RETURN(0);
  300.   }
  301.   int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags)
  302.   {
  303.     char from_tmp[FN_REFLEN];
  304.     uint from_pos = dirname_length(from);
  305.     DBUG_ENTER("my_raid_delete");
  306.     if (!raid_chunks)
  307.       DBUG_RETURN(my_delete(from,MyFlags));
  308.     for (uint i = 0 ; i < raid_chunks ; i++ )
  309.     {
  310.       memcpy(from_tmp, from, from_pos);
  311.       sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
  312.       /* Convert if not unix */
  313.       unpack_filename(from_tmp, from_tmp);
  314.       if (my_delete(from_tmp, MyFlags))
  315. DBUG_RETURN(-1);
  316.     }
  317.     DBUG_RETURN(0);
  318.   }
  319.   int my_raid_redel(const char *old_name, const char *new_name,
  320.     uint raid_chunks, myf MyFlags)
  321.   {
  322.     char new_name_buff[FN_REFLEN], old_name_buff[FN_REFLEN];
  323.     char *new_end, *old_end;
  324.     uint i,old_length,new_length;
  325.     int error=0;
  326.     DBUG_ENTER("my_raid_redel");
  327.     old_end=old_name_buff+dirname_part(old_name_buff,old_name);
  328.     old_length=dirname_length(old_name);
  329.     new_end=new_name_buff+dirname_part(new_name_buff,new_name);
  330.     new_length=dirname_length(new_name);
  331.     for (i=0 ; i < raid_chunks ; i++)
  332.     {
  333.       MY_STAT status;
  334.       sprintf(new_end,"%02x",i);
  335.       if (my_stat(new_name_buff,&status, MYF(0)))
  336.       {
  337. DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
  338.       }
  339.       else
  340.       {
  341. if (my_mkdir(new_name_buff,0777,MYF(0)))
  342. {
  343.   DBUG_PRINT("error",("mkdir failed for %02x",i));
  344.   DBUG_RETURN(-1);
  345. }
  346.       }
  347.       strxmov(strend(new_end),"/",new_name+new_length,NullS);
  348.       sprintf(old_end,"%02x/%s",i, old_name+old_length);
  349.       if (my_redel(old_name_buff, new_name_buff, MyFlags))
  350. error=1;
  351.     }
  352.     DBUG_RETURN(error);
  353.   }
  354. }
  355. int my_raid_fstat(int fd, MY_STAT *stat_area, myf MyFlags )
  356. {
  357.   DBUG_ENTER("my_raid_fstat");
  358.   if (is_raid(fd))
  359.   {
  360.     RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  361.     DBUG_RETURN(raid->Fstat(fd, stat_area, MyFlags));
  362.   }
  363.   else
  364.     DBUG_RETURN(my_fstat(fd, stat_area, MyFlags));
  365. }
  366. /* -------------- RaidFd base class begins ----------------*/
  367. /*
  368.   RaidFd - raided file is identified by file descriptor
  369.   this is useful when we open/write/read/close files
  370. */
  371. bool RaidFd::
  372. IsRaid(File fd)
  373. {
  374.   DBUG_ENTER("RaidFd::IsRaid");
  375.   DBUG_RETURN((uint) fd < _raid_map.elements &&
  376.       *dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
  377. }
  378. RaidFd::
  379. RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize)
  380.   :_raid_type(raid_type), _raid_chunks(raid_chunks),
  381.    _raid_chunksize(raid_chunksize), _position(0), _fd_vector(0),
  382.    _size(RAID_SIZE_UNKNOWN)
  383. {
  384.   DBUG_ENTER("RaidFd::RaidFd");
  385.   DBUG_PRINT("enter",("RaidFd_type: %u  Disks: %u  Chunksize: %d",
  386.    raid_type, raid_chunks, raid_chunksize));
  387.   /* TODO: Here we should add checks if the malloc fails */
  388.   _seek_vector=0; /* In case of errors */
  389.   my_multi_malloc(MYF(MY_WME),
  390.   &_seek_vector,sizeof(off_t)*_raid_chunks,
  391.   &_fd_vector, sizeof(File) *_raid_chunks,
  392.   NullS);
  393.   if (!RaidFd::_raid_map.buffer)
  394.   { /* Not initied */
  395.     pthread_mutex_lock(&THR_LOCK_open); /* Ensure that no other thread */
  396.     if (!RaidFd::_raid_map.buffer) /* has done init in between */
  397.       init_raid();
  398.     pthread_mutex_unlock(&THR_LOCK_open);
  399.   }
  400.   DBUG_VOID_RETURN;
  401. }
  402. RaidFd::
  403. ~RaidFd() {
  404.   DBUG_ENTER("RaidFd::~RaidFd");
  405.   /* We don't have to free _fd_vector ! */
  406.   my_free((char*) _seek_vector, MYF(MY_ALLOW_ZERO_PTR));
  407.   DBUG_VOID_RETURN;
  408. }
  409. File RaidFd::
  410. Create(const char *FileName, int CreateFlags, int access_flags, myf MyFlags)
  411. {
  412.   char RaidFdFileName[FN_REFLEN];
  413.   DBUG_ENTER("RaidFd::Create");
  414.   DBUG_PRINT("enter",
  415.      ("FileName: %s  CreateFlags: %d  access_flags: %d  MyFlags: %d",
  416.       FileName, CreateFlags, access_flags, MyFlags));
  417.   char DirName[FN_REFLEN];
  418.   uint pos = dirname_part(DirName, FileName);
  419.   MY_STAT status;
  420.   if (!_seek_vector)
  421.     DBUG_RETURN(-1); /* Not enough memory */
  422.   uint i = _raid_chunks-1;
  423.   do
  424.   {
  425.     /* Create subdir */
  426.     (void)sprintf(RaidFdFileName,"%s%02x", DirName,i);
  427.     unpack_dirname(RaidFdFileName,RaidFdFileName);   /* Convert if not unix */
  428.     if (my_stat(RaidFdFileName,&status, MYF(0)))
  429.     {
  430.       DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
  431.     }
  432.     else
  433.     {
  434.       if (my_mkdir(RaidFdFileName,0777,MYF(0)))
  435.       {
  436. DBUG_PRINT("error",("mkdir failed for %d",i));
  437. goto error;
  438.       }
  439.     }
  440.     /* Create file */
  441.     sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
  442.     unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
  443.     _fd = my_create(RaidFdFileName, CreateFlags ,access_flags, (myf)MyFlags);
  444.     if (_fd < 0)
  445.       goto error;
  446.     _fd_vector[i]=_fd;
  447.     _seek_vector[i]=RAID_SEEK_DONE;
  448.   } while (i--);
  449.   _size=0;
  450.   DBUG_RETURN(_fd); /* Last filenr is pointer to map */
  451. error:
  452.   {
  453.     int save_errno=my_errno;
  454.     while (++i < _raid_chunks)
  455.     {
  456.       my_close(_fd_vector[i],MYF(0));
  457.       sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
  458.       unpack_filename(RaidFdFileName,RaidFdFileName);
  459.       my_delete(RaidFdFileName,MYF(0));
  460.     }
  461.     my_errno=save_errno;
  462.   }
  463.   DBUG_RETURN(-1);
  464. }
  465. File RaidFd::
  466. Open(const char *FileName, int Flags, myf MyFlags)
  467. {
  468.   DBUG_ENTER("RaidFd::Open");
  469.   DBUG_PRINT("enter",("FileName: %s  Flags: %d  MyFlags: %d",
  470.    FileName, Flags, MyFlags));
  471.   char DirName[FN_REFLEN];
  472.   uint pos = dirname_part(DirName, FileName);
  473.   if (!_seek_vector)
  474.     DBUG_RETURN(-1); /* Not enough memory */
  475.   for( uint i = 0 ;  i < _raid_chunks ; i++ )
  476.   {
  477.     char RaidFdFileName[FN_REFLEN];
  478.     sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
  479.     unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
  480.     _fd = my_open(RaidFdFileName, Flags, MyFlags);
  481.     if (_fd < 0)
  482.     {
  483.       int save_errno=my_errno;
  484.       while (i-- != 0)
  485. my_close(_fd_vector[i],MYF(0));
  486.       my_errno=save_errno;
  487.       DBUG_RETURN(_fd);
  488.     }
  489.     _fd_vector[i]=_fd;
  490.     _seek_vector[i]=RAID_SEEK_DONE;
  491.   }
  492.   Seek(0L,MY_SEEK_END,MYF(0)); // Trick. We just need to know, how big the file is
  493.   DBUG_PRINT("info",("MYD file logical size: %llu", _size));
  494.   DBUG_RETURN(_fd);
  495. }
  496. int RaidFd::
  497. Write(const byte *Buffer, uint Count, myf MyFlags)
  498. {
  499.   DBUG_ENTER("RaidFd::Write");
  500.   DBUG_PRINT("enter",("Count: %d  MyFlags: %d",
  501.       Count, MyFlags));
  502.   const byte *bufptr = Buffer;
  503.   uint res=0, GotBytes, ReadNowCount;
  504.   // Loop until data is written
  505.   do {
  506.     Calculate();
  507.      // Do seeks when neccessary
  508.     if (_seek_vector[_this_block] != RAID_SEEK_DONE)
  509.     {
  510.       if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
  511.   MY_SEEK_SET,
  512.   MyFlags) == MY_FILEPOS_ERROR)
  513. DBUG_RETURN(-1);
  514.       _seek_vector[_this_block]=RAID_SEEK_DONE;
  515.     }
  516.     ReadNowCount = min(Count, _remaining_bytes);
  517.     GotBytes = my_write(_fd_vector[_this_block], bufptr, ReadNowCount,
  518. MyFlags);
  519.     DBUG_PRINT("loop",("Wrote bytes: %d", GotBytes));
  520.     if (GotBytes == MY_FILE_ERROR)
  521.       DBUG_RETURN(-1);
  522.     res+= GotBytes;
  523.     if (MyFlags & (MY_NABP | MY_FNABP))
  524.       GotBytes=ReadNowCount;
  525.     bufptr += GotBytes;
  526.     Count  -= GotBytes;
  527.     _position += GotBytes;
  528.   } while(Count);
  529.   set_if_bigger(_size,_position);
  530.   DBUG_RETURN(res);
  531. }
  532. int RaidFd::
  533. Read(const byte *Buffer, uint Count, myf MyFlags)
  534. {
  535.   DBUG_ENTER("RaidFd::Read");
  536.   DBUG_PRINT("enter",("Count: %d  MyFlags: %d",
  537.       Count, MyFlags));
  538.   byte *bufptr = (byte *)Buffer;
  539.   uint res= 0, GotBytes, ReadNowCount;
  540.   // Loop until all data is read (Note that Count may be 0)
  541.   while (Count)
  542.   {
  543.     Calculate();
  544.     // Do seek when neccessary
  545.     if (_seek_vector[_this_block] != RAID_SEEK_DONE)
  546.     {
  547.       if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
  548.   MY_SEEK_SET,
  549.   MyFlags) == MY_FILEPOS_ERROR)
  550. DBUG_RETURN(-1);
  551.       _seek_vector[_this_block]=RAID_SEEK_DONE;
  552.     }
  553.     // and read
  554.     ReadNowCount = min(Count, _remaining_bytes);
  555.     GotBytes = my_read(_fd_vector[_this_block], bufptr, ReadNowCount,
  556.        MyFlags & ~(MY_NABP | MY_FNABP));
  557.     DBUG_PRINT("loop",("Got bytes: %u", GotBytes));
  558.     if (GotBytes == MY_FILE_ERROR)
  559.       DBUG_RETURN(-1);
  560.     if (!GotBytes) // End of file.
  561.     {
  562.       DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? -1 : (int) res);
  563.     }
  564.     res+= GotBytes;
  565.     bufptr += GotBytes;
  566.     Count  -= GotBytes;
  567.     _position += GotBytes;
  568.   }
  569.   DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? 0 : res);
  570. }
  571. int RaidFd::
  572. Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags)
  573. {
  574.   DBUG_ENTER("RaidFd::Lock");
  575.   DBUG_PRINT("enter",("locktype: %d  start: %lu  length: %lu  MyFlags: %d",
  576.       locktype, start, length, MyFlags));
  577.   my_off_t bufptr = start;
  578.   // Loop until all data is locked
  579.   while(length)
  580.   {
  581.     Calculate();
  582.     for (uint i = _this_block ; (i < _raid_chunks) && length ; i++ )
  583.     {
  584.        uint ReadNowCount = min(length, _remaining_bytes);
  585.        uint GotBytes = my_lock(_fd_vector[i], locktype, bufptr, ReadNowCount,
  586. MyFlags);
  587.        if ((int) GotBytes == -1)
  588.  DBUG_RETURN(-1);
  589.        bufptr += ReadNowCount;
  590.        length  -= ReadNowCount;
  591.        Calculate();
  592.     }
  593.   }
  594.   DBUG_RETURN(0);
  595. }
  596. int RaidFd::
  597. Close(myf MyFlags)
  598. {
  599.   DBUG_ENTER("RaidFd::Close");
  600.   DBUG_PRINT("enter",("MyFlags: %d",
  601.    MyFlags));
  602.   for (uint i = 0 ; i < _raid_chunks ; ++i )
  603.   {
  604.     int err = my_close(_fd_vector[i], MyFlags);
  605.     if (err != 0)
  606.       DBUG_RETURN(err);
  607.   }
  608.   /* _fd_vector is erased when RaidFd is released */
  609.   DBUG_RETURN(0);
  610. }
  611. my_off_t RaidFd::
  612. Seek(my_off_t pos,int whence,myf MyFlags)
  613. {
  614.   DBUG_ENTER("RaidFd::Seek");
  615.   DBUG_PRINT("enter",("Pos: %lu  Whence: %d  MyFlags: %d",
  616.    (ulong) pos, whence, MyFlags));
  617.   switch (whence) {
  618.   case MY_SEEK_CUR:
  619.     // FIXME: This is wrong, what is going on there
  620.     // Just I am relied on fact that MySQL 3.23.7 never uses MY_SEEK_CUR
  621.     // for anything else except things like ltell()
  622.     break;
  623.   case MY_SEEK_SET:
  624.     if ( _position != pos) // we can be already in right place
  625.     {
  626.       uint i;
  627.       off_t _rounds;
  628.       _position = pos;
  629.       Calculate();
  630.       _rounds = _total_block / _raid_chunks;     // INT() assumed
  631.       _rounds*= _raid_chunksize;
  632.       for (i = 0; i < _raid_chunks ; i++ )
  633. if ( i < _this_block )
  634.   _seek_vector[i] = _rounds + _raid_chunksize;
  635. else if ( i == _this_block )
  636.   _seek_vector[i] = _rounds + _raid_chunksize -_remaining_bytes;
  637. else // if ( i > _this_block )
  638.   _seek_vector[i] = _rounds;
  639.     }
  640.     break;
  641.   case MY_SEEK_END:
  642.     if (_size==RAID_SIZE_UNKNOWN) // We don't know table size yet
  643.     {
  644.       uint i;
  645.       _position = 0;
  646.       for (i = 0; i < _raid_chunks ; i++ )
  647.       {
  648. my_off_t newpos = my_seek(_fd_vector[i], 0L, MY_SEEK_END, MyFlags);
  649. if (newpos == MY_FILEPOS_ERROR)
  650.   DBUG_RETURN (MY_FILEPOS_ERROR);
  651. _seek_vector[i]=RAID_SEEK_DONE;
  652. _position += newpos;
  653.       }
  654.       _size=_position;
  655.     }
  656.     else if (_position != _size) // Aren't we also already in the end?
  657.     {
  658.       uint i;
  659.       off_t _rounds;
  660.       _position = _size;
  661.       Calculate();
  662.       _rounds = _total_block / _raid_chunks;     // INT() assumed
  663.       _rounds*= _raid_chunksize;
  664.       for (i = 0; i < _raid_chunks ; i++ )
  665. if ( i < _this_block )
  666.   _seek_vector[i] = _rounds + _raid_chunksize;
  667. else if ( i == _this_block )
  668.   _seek_vector[i] = _rounds + _raid_chunksize - _remaining_bytes;
  669. else // if ( i > _this_block )
  670.   _seek_vector[i] = _rounds;
  671.       _position=_size;
  672.     }
  673.   }
  674.   DBUG_RETURN(_position);
  675. }
  676. my_off_t RaidFd::
  677. Tell(myf MyFlags)
  678. {
  679.   DBUG_ENTER("RaidFd::Tell");
  680.   DBUG_PRINT("enter",("MyFlags: %d _position %d",
  681.    MyFlags,_position));
  682.   DBUG_RETURN(_position);
  683. }
  684. int RaidFd::
  685. Chsize(File fd, my_off_t newlength, myf MyFlags)
  686. {
  687.   DBUG_ENTER("RaidFd::Chsize");
  688.   DBUG_PRINT("enter",("Fd: %d, newlength: %d, MyFlags: %d",
  689.    fd, newlength,MyFlags));
  690.   _position = newlength;
  691.   Calculate();
  692.   uint _rounds = _total_block / _raid_chunks;      // INT() assumed
  693.   for (uint i = 0; i < _raid_chunks ; i++ )
  694.   {
  695.     int newpos;
  696.     if ( i < _this_block )
  697.       newpos = my_chsize(_fd_vector[i],
  698.  _this_block * _raid_chunksize + (_rounds + 1) *
  699.  _raid_chunksize,
  700.  MyFlags);
  701.     else if ( i == _this_block )
  702.       newpos = my_chsize(_fd_vector[i],
  703.  _this_block * _raid_chunksize + _rounds *
  704.  _raid_chunksize + (newlength % _raid_chunksize),
  705.  MyFlags);
  706.     else // this means: i > _this_block
  707.       newpos = my_chsize(_fd_vector[i],
  708.  _this_block * _raid_chunksize + _rounds *
  709.  _raid_chunksize, MyFlags);
  710.     if (newpos)
  711.       DBUG_RETURN(1);
  712.   }
  713.   DBUG_RETURN(0);
  714. }
  715. int RaidFd::
  716. Fstat(int fd, MY_STAT *stat_area, myf MyFlags )
  717. {
  718.   DBUG_ENTER("RaidFd::Fstat");
  719.   DBUG_PRINT("enter",("fd: %d MyFlags: %d",fd,MyFlags));
  720.   uint i;
  721.   int error=0;
  722.   MY_STAT my_stat;
  723.   stat_area->st_size=0;
  724.   stat_area->st_mtime=0;
  725.   stat_area->st_atime=0;
  726.   stat_area->st_ctime=0;
  727.   for(i=0 ; i < _raid_chunks ; i++)
  728.   {
  729.     if (my_fstat(_fd_vector[i],&my_stat,MyFlags))
  730.       error=1;
  731.     stat_area->st_size+=my_stat.st_size;
  732.     set_if_bigger(stat_area->st_mtime,my_stat.st_mtime);
  733.     set_if_bigger(stat_area->st_atime,my_stat.st_atime);
  734.     set_if_bigger(stat_area->st_ctime,my_stat.st_ctime);
  735.   }
  736.   DBUG_RETURN(error);
  737. }
  738. #endif /* defined(USE_RAID) && !defined(MYSQL_CLIENT) */