diff options
Diffstat (limited to 'mysys/raid.cc')
-rw-r--r-- | mysys/raid.cc | 809 |
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) */ |