home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / mysys / raid.cpp < prev    next >
C/C++ Source or Header  |  2000-08-31  |  24KB  |  810 lines

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