00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #include <config.h>
00051
00052 #include <drizzled/definitions.h>
00053 #include <drizzled/error_t.h>
00054 #include <drizzled/error.h>
00055 #include <drizzled/internal/my_sys.h>
00056 #include <drizzled/internal/m_string.h>
00057 #include <drizzled/drizzled.h>
00058 #include <drizzled/internal/iocache.h>
00059 #include <errno.h>
00060 #include <drizzled/util/test.h>
00061 #include <stdlib.h>
00062 #include <algorithm>
00063
00064 using namespace std;
00065
00066 namespace drizzled {
00067 namespace internal {
00068
00069 static int _my_b_read(io_cache_st *info, unsigned char *Buffer, size_t Count);
00070 static int _my_b_write(io_cache_st *info, const unsigned char *Buffer, size_t Count);
00071
00076 inline
00077 static void lock_append_buffer(io_cache_st *, int )
00078 {
00079 }
00080
00085 inline
00086 static void unlock_append_buffer(io_cache_st *, int )
00087 {
00088 }
00089
00094 inline
00095 static size_t io_round_up(size_t x)
00096 {
00097 return ((x+IO_SIZE-1) & ~(IO_SIZE-1));
00098 }
00099
00104 inline
00105 static size_t io_round_dn(size_t x)
00106 {
00107 return (x & ~(IO_SIZE-1));
00108 }
00109
00110
00121 void io_cache_st::setup_io_cache()
00122 {
00123
00124 if (type == WRITE_CACHE)
00125 {
00126 current_pos= &write_pos;
00127 current_end= &write_end;
00128 }
00129 else
00130 {
00131 current_pos= &read_pos;
00132 current_end= &read_end;
00133 }
00134 }
00135
00136
00137 void io_cache_st::init_functions()
00138 {
00139 switch (type) {
00140 case READ_NET:
00141
00142
00143
00144
00145
00146
00147
00148 break;
00149 default:
00150 read_function = _my_b_read;
00151 write_function = _my_b_write;
00152 }
00153
00154 setup_io_cache();
00155 }
00156
00174 int io_cache_st::init_io_cache(int file_arg, size_t cachesize,
00175 enum cache_type type_arg, my_off_t seek_offset,
00176 bool use_async_io, myf cache_myflags)
00177 {
00178 size_t min_cache;
00179 off_t pos;
00180 my_off_t end_of_file_local= ~(my_off_t) 0;
00181
00182 file= file_arg;
00183 type= TYPE_NOT_SET;
00184 pos_in_file= seek_offset;
00185 pre_close = pre_read = post_read = 0;
00186 arg = 0;
00187 alloced_buffer = 0;
00188 buffer=0;
00189 seek_not_done= 0;
00190
00191 if (file >= 0)
00192 {
00193 pos= lseek(file, 0, SEEK_CUR);
00194 if ((pos == MY_FILEPOS_ERROR) && (errno == ESPIPE))
00195 {
00196
00197
00198
00199
00200 seek_not_done= 0;
00201
00202
00203
00204
00205
00206 assert(seek_offset == 0);
00207 }
00208 else
00209 seek_not_done= test(seek_offset != (my_off_t)pos);
00210 }
00211
00212 if (!cachesize && !(cachesize= my_default_record_cache_size))
00213 return 1;
00214 min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
00215 if (type_arg == READ_CACHE)
00216 {
00217 if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
00218 {
00219
00220 end_of_file_local=lseek(file,0L,SEEK_END);
00221
00222 seek_not_done= end_of_file_local == seek_offset ? 0 : 1;
00223 if (end_of_file_local < seek_offset)
00224 end_of_file_local=seek_offset;
00225
00226 if ((my_off_t) cachesize > end_of_file_local-seek_offset+IO_SIZE*2-1)
00227 {
00228 cachesize= (size_t) (end_of_file_local-seek_offset)+IO_SIZE*2-1;
00229 use_async_io=0;
00230 }
00231 }
00232 }
00233 cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
00234 if (type_arg != READ_NET && type_arg != WRITE_NET)
00235 {
00236
00237 cachesize= ((cachesize + min_cache-1) & ~(min_cache-1));
00238 if (cachesize < min_cache)
00239 cachesize = min_cache;
00240 size_t buffer_block= cachesize;
00241 if (type_arg == READ_CACHE && not global_read_buffer.add(buffer_block))
00242 {
00243 my_error(ER_OUT_OF_GLOBAL_READMEMORY, MYF(ME_ERROR+ME_WAITTANG));
00244 return 2;
00245 }
00246
00247 buffer= (unsigned char*) malloc(buffer_block);
00248 write_buffer=buffer;
00249 alloced_buffer= true;
00250 }
00251
00252 read_length=buffer_length=cachesize;
00253 myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
00254 request_pos= read_pos= write_pos = buffer;
00255
00256 if (type_arg == WRITE_CACHE)
00257 write_end=
00258 buffer+buffer_length- (seek_offset & (IO_SIZE-1));
00259 else
00260 read_end=buffer;
00261
00262
00263 end_of_file= end_of_file_local;
00264 error= 0;
00265 type= type_arg;
00266 init_functions();
00267 return 0;
00268 }
00269
00280 bool io_cache_st::reinit_io_cache(enum cache_type type_arg,
00281 my_off_t seek_offset,
00282 bool,
00283 bool clear_cache)
00284 {
00285
00286 assert(type_arg != READ_NET && type != READ_NET &&
00287 type_arg != WRITE_NET && type != WRITE_NET);
00288
00289
00290 if (! clear_cache &&
00291 seek_offset >= pos_in_file &&
00292 seek_offset <= tell())
00293 {
00294
00295 unsigned char *pos;
00296 if (type == WRITE_CACHE && type_arg == READ_CACHE)
00297 {
00298 read_end=write_pos;
00299 end_of_file= tell();
00300
00301
00302
00303
00304 seek_not_done= (file != -1);
00305 }
00306 else if (type_arg == WRITE_CACHE)
00307 {
00308 if (type == READ_CACHE)
00309 {
00310 write_end=write_buffer+buffer_length;
00311 seek_not_done=1;
00312 }
00313 end_of_file = ~(my_off_t) 0;
00314 }
00315 pos=request_pos+(seek_offset-pos_in_file);
00316 if (type_arg == WRITE_CACHE)
00317 write_pos=pos;
00318 else
00319 read_pos= pos;
00320 }
00321 else
00322 {
00323
00324
00325
00326
00327 if (type == WRITE_CACHE && type_arg == READ_CACHE)
00328 end_of_file= tell();
00329
00330 if (!clear_cache && flush(1))
00331 return 1;
00332 pos_in_file=seek_offset;
00333
00334 seek_not_done=1;
00335 request_pos=read_pos=write_pos=buffer;
00336 if (type_arg == READ_CACHE)
00337 {
00338 read_end=buffer;
00339 }
00340 else
00341 {
00342 write_end= (buffer + buffer_length - (seek_offset & (IO_SIZE-1)));
00343 end_of_file= ~(my_off_t) 0;
00344 }
00345 }
00346 type= type_arg;
00347 error=0;
00348 init_functions();
00349
00350 return 0;
00351 }
00352
00373 static int _my_b_read(io_cache_st *info, unsigned char *Buffer, size_t Count)
00374 {
00375 size_t length_local,diff_length,left_length, max_length;
00376 my_off_t pos_in_file_local;
00377
00378 if ((left_length= (size_t) (info->read_end-info->read_pos)))
00379 {
00380 assert(Count >= left_length);
00381 memcpy(Buffer,info->read_pos, left_length);
00382 Buffer+=left_length;
00383 Count-=left_length;
00384 }
00385
00386
00387 pos_in_file_local=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
00388
00389
00390
00391
00392
00393
00394
00395 if (info->seek_not_done)
00396 {
00397 if ((lseek(info->file,pos_in_file_local,SEEK_SET) != MY_FILEPOS_ERROR))
00398 {
00399
00400 info->seek_not_done= 0;
00401 }
00402 else
00403 {
00404
00405
00406
00407
00408
00409 assert(errno != ESPIPE);
00410 info->error= -1;
00411 return 1;
00412 }
00413 }
00414
00415 diff_length= (size_t) (pos_in_file_local & (IO_SIZE-1));
00416 if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
00417 {
00418 size_t read_length;
00419 if (info->end_of_file <= pos_in_file_local)
00420 {
00421 info->error= (int) left_length;
00422 return 1;
00423 }
00424 length_local=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
00425 if ((read_length= my_read(info->file,Buffer, length_local, info->myflags)) != length_local)
00426 {
00427 info->error= (read_length == (size_t) -1 ? -1 :
00428 (int) (read_length+left_length));
00429 return 1;
00430 }
00431 Count-= length_local;
00432 Buffer+= length_local;
00433 pos_in_file_local+= length_local;
00434 left_length+= length_local;
00435 diff_length=0;
00436 }
00437
00438 max_length= info->read_length-diff_length;
00439 if (info->type != READ_FIFO &&
00440 max_length > (info->end_of_file - pos_in_file_local))
00441 max_length= (size_t) (info->end_of_file - pos_in_file_local);
00442 if (!max_length)
00443 {
00444 if (Count)
00445 {
00446 info->error= static_cast<int>(left_length);
00447 return 1;
00448 }
00449 length_local=0;
00450 }
00451 else if (( length_local= my_read(info->file,info->buffer, max_length,
00452 info->myflags)) < Count ||
00453 length_local == (size_t) -1)
00454 {
00455 if ( length_local != (size_t) -1)
00456 memcpy(Buffer, info->buffer, length_local);
00457 info->pos_in_file= pos_in_file_local;
00458 info->error= length_local == (size_t) -1 ? -1 : (int) ( length_local+left_length);
00459 info->read_pos=info->read_end=info->buffer;
00460 return 1;
00461 }
00462 info->read_pos=info->buffer+Count;
00463 info->read_end=info->buffer+ length_local;
00464 info->pos_in_file=pos_in_file_local;
00465 memcpy(Buffer, info->buffer, Count);
00466 return 0;
00467 }
00468
00473 int io_cache_st::get()
00474 {
00475 if (read_pos != read_end)
00476 return *read_pos++;
00477
00478 if (pre_read)
00479 pre_read(this);
00480
00481 unsigned char buff;
00482 if (read_function(this, &buff, 1))
00483 return my_b_EOF;
00484
00485 if (post_read)
00486 post_read(this);
00487
00488 return buff;
00489 }
00490
00499 int _my_b_write(io_cache_st *info, const unsigned char *Buffer, size_t Count)
00500 {
00501 size_t rest_length,length_local;
00502
00503 if (info->pos_in_file+info->buffer_length > info->end_of_file)
00504 {
00505 errno=EFBIG;
00506 return info->error = -1;
00507 }
00508
00509 rest_length= (size_t) (info->write_end - info->write_pos);
00510 memcpy(info->write_pos,Buffer,(size_t) rest_length);
00511 Buffer+=rest_length;
00512 Count-=rest_length;
00513 info->write_pos+=rest_length;
00514
00515 if (info->flush(1))
00516 return 1;
00517 if (Count >= IO_SIZE)
00518 {
00519 length_local=Count & (size_t) ~(IO_SIZE-1);
00520 if (info->seek_not_done)
00521 {
00522
00523
00524
00525
00526
00527
00528 if (lseek(info->file,info->pos_in_file,SEEK_SET))
00529 {
00530 info->error= -1;
00531 return (1);
00532 }
00533 info->seek_not_done=0;
00534 }
00535 if (my_write(info->file, Buffer, length_local, info->myflags | MY_NABP))
00536 return info->error= -1;
00537
00538 Count-=length_local;
00539 Buffer+=length_local;
00540 info->pos_in_file+=length_local;
00541 }
00542 memcpy(info->write_pos,Buffer,(size_t) Count);
00543 info->write_pos+=Count;
00544 return 0;
00545 }
00546
00553 static int my_block_write(io_cache_st *info, const unsigned char *Buffer, size_t Count, my_off_t pos)
00554 {
00555 size_t length_local;
00556 int error=0;
00557
00558 if (pos < info->pos_in_file)
00559 {
00560
00561 if (pos + Count <= info->pos_in_file)
00562 return (pwrite(info->file, Buffer, Count, pos) == 0);
00563
00564 length_local= (uint32_t) (info->pos_in_file - pos);
00565 if (pwrite(info->file, Buffer, length_local, pos) == 0)
00566 info->error= error= -1;
00567 Buffer+=length_local;
00568 pos+= length_local;
00569 Count-= length_local;
00570 }
00571
00572
00573 length_local= (size_t) (info->write_end - info->buffer);
00574 if (pos < info->pos_in_file + length_local)
00575 {
00576 size_t offset= (size_t) (pos - info->pos_in_file);
00577 length_local-=offset;
00578 if (length_local > Count)
00579 length_local=Count;
00580 memcpy(info->buffer+offset, Buffer, length_local);
00581 Buffer+=length_local;
00582 Count-= length_local;
00583
00584 if (info->buffer+length_local > info->write_pos)
00585 info->write_pos=info->buffer+length_local;
00586 if (!Count)
00587 return (error);
00588 }
00589
00590 if (_my_b_write(info, Buffer, Count))
00591 error= -1;
00592 return error;
00593 }
00594
00595 int io_cache_st::block_write(const void* Buffer, size_t Count, my_off_t pos)
00596 {
00597 return my_block_write(this, reinterpret_cast<const unsigned char*>(Buffer), Count, pos);
00598 }
00599
00604 static int my_b_flush_io_cache(io_cache_st *info, int need_append_buffer_lock)
00605 {
00606 size_t length_local;
00607 bool append_cache= false;
00608 my_off_t pos_in_file_local;
00609
00610 if (info->type == WRITE_CACHE || append_cache)
00611 {
00612 if (info->file == -1)
00613 {
00614 if (info->real_open_cached_file())
00615 return((info->error= -1));
00616 }
00617 lock_append_buffer(info, need_append_buffer_lock);
00618
00619 if ((length_local=(size_t) (info->write_pos - info->write_buffer)))
00620 {
00621 pos_in_file_local=info->pos_in_file;
00622
00623
00624
00625
00626 if (!append_cache && info->seek_not_done)
00627 {
00628 if (lseek(info->file,pos_in_file_local,SEEK_SET) == MY_FILEPOS_ERROR)
00629 {
00630 unlock_append_buffer(info, need_append_buffer_lock);
00631 return((info->error= -1));
00632 }
00633 if (!append_cache)
00634 info->seek_not_done=0;
00635 }
00636 if (!append_cache)
00637 info->pos_in_file+=length_local;
00638 info->write_end= (info->write_buffer+info->buffer_length-
00639 ((pos_in_file_local+length_local) & (IO_SIZE-1)));
00640
00641 if (my_write(info->file,info->write_buffer,length_local,
00642 info->myflags | MY_NABP))
00643 info->error= -1;
00644 else
00645 info->error= 0;
00646 if (!append_cache)
00647 {
00648 set_if_bigger(info->end_of_file,(pos_in_file_local+length_local));
00649 }
00650 else
00651 {
00652 info->end_of_file+=(info->write_pos-info->append_read_pos);
00653 my_off_t tell_ret= lseek(info->file, 0, SEEK_CUR);
00654 assert(info->end_of_file == tell_ret);
00655 }
00656
00657 info->append_read_pos=info->write_pos=info->write_buffer;
00658 unlock_append_buffer(info, need_append_buffer_lock);
00659 return(info->error);
00660 }
00661 }
00662 unlock_append_buffer(info, need_append_buffer_lock);
00663 return 0;
00664 }
00665
00666 int io_cache_st::flush(int need_append_buffer_lock)
00667 {
00668 return my_b_flush_io_cache(this, need_append_buffer_lock);
00669 }
00670
00685 int io_cache_st::end_io_cache()
00686 {
00687 int _error=0;
00688
00689 if (pre_close)
00690 {
00691 (*pre_close)(this);
00692 pre_close= 0;
00693 }
00694 if (alloced_buffer)
00695 {
00696 if (type == READ_CACHE)
00697 global_read_buffer.sub(buffer_length);
00698 alloced_buffer=0;
00699 if (file != -1)
00700 _error= my_b_flush_io_cache(this, 1);
00701 free((unsigned char*) buffer);
00702 buffer=read_pos=(unsigned char*) 0;
00703 }
00704
00705 return _error;
00706 }
00707
00708 }
00709 }