mirror of https://github.com/MariaDB/server
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							798 lines
						
					
					
						
							23 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							798 lines
						
					
					
						
							23 KiB
						
					
					
				| /* 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; version 2 of the License. | |
|  | |
|    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: 0x%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: 0x%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: 0x%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: 0x%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: %lu  length: %lu  MyFlags: %d", | |
|                         fd, (ulong) start, (ulong) 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: %lu  MyFlags: %d", | |
|                         fd, (ulong) 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: %lu", | |
| 		   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, (ulong) start, (ulong) 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: %lu", | |
|                       MyFlags, (ulong) _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: %lu  MyFlags: %d", | |
|                       fd, (ulong) 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) */
 |