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