1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
|
/* 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) */
|