summaryrefslogtreecommitdiff
path: root/mysys/raid.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/raid.cc')
-rw-r--r--mysys/raid.cc809
1 files changed, 809 insertions, 0 deletions
diff --git a/mysys/raid.cc b/mysys/raid.cc
new file mode 100644
index 00000000000..a92647d1d95
--- /dev/null
+++ b/mysys/raid.cc
@@ -0,0 +1,809 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; 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 __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysys_priv.h"
+#include "my_dir.h"
+#include <m_string.h>
+#include <assert.h>
+
+const char *raid_type_string[]={"none","striped"};
+
+
+extern "C" {
+ const char *my_raid_type(int raid_type)
+ {
+ return raid_type_string[raid_type];
+ }
+}
+
+#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 */
+ 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));
+
+ assert(pos != MY_FILEPOS_ERROR);
+
+ if (is_raid(fd))
+ {
+ 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: %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: %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: %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: %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, 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, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_chsize(fd, newlength, 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), _fd_vector(0),
+ _size(RAID_SIZE_UNKNOWN)
+{
+ 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, 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,
+ MyFlags);
+ else if ( i == _this_block )
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + _rounds *
+ _raid_chunksize + (newlength % _raid_chunksize),
+ MyFlags);
+ else // this means: i > _this_block
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + _rounds *
+ _raid_chunksize, 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 my_stat;
+ 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],&my_stat,MyFlags))
+ error=1;
+ stat_area->st_size+=my_stat.st_size;
+ set_if_bigger(stat_area->st_mtime,my_stat.st_mtime);
+ set_if_bigger(stat_area->st_atime,my_stat.st_atime);
+ set_if_bigger(stat_area->st_ctime,my_stat.st_ctime);
+ }
+ DBUG_RETURN(error);
+}
+
+#endif /* defined(USE_RAID) && !defined(MYSQL_CLIENT) */