Drizzled Public API Documentation

records.cc
Go to the documentation of this file.
00001 /* Copyright (C) 2000-2006 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00022 #include <config.h>
00023 
00024 #include <drizzled/drizzled.h>
00025 #include <drizzled/error.h>
00026 #include <drizzled/internal/iocache.h>
00027 #include <drizzled/internal/my_sys.h>
00028 #include <drizzled/optimizer/range.h>
00029 #include <drizzled/plugin/storage_engine.h>
00030 #include <drizzled/records.h>
00031 #include <drizzled/session.h>
00032 #include <drizzled/table.h>
00033 #include <drizzled/system_variables.h>
00034 
00035 namespace drizzled {
00036 
00037 static int rr_sequential(ReadRecord *info);
00038 static int rr_quick(ReadRecord *info);
00039 static int rr_from_tempfile(ReadRecord *info);
00040 static int rr_unpack_from_tempfile(ReadRecord *info);
00041 static int rr_unpack_from_buffer(ReadRecord *info);
00042 static int rr_from_pointers(ReadRecord *info);
00043 static int rr_from_cache(ReadRecord *info);
00044 static int rr_cmp(unsigned char *a,unsigned char *b);
00045 static int rr_index_first(ReadRecord *info);
00046 static int rr_index(ReadRecord *info);
00047 
00048 void ReadRecord::init_reard_record_sequential()
00049 {
00050   read_record= rr_sequential;
00051 }
00052 
00053 int ReadRecord::init_read_record_idx(Session *,
00054                                      Table *table_arg,
00055                                      bool print_error_arg,
00056                                      uint32_t idx)
00057 {
00058   table_arg->emptyRecord();
00059   table= table_arg;
00060   cursor=  table->cursor;
00061   record= table->getInsertRecord();
00062   print_error= print_error_arg;
00063 
00064   table->status=0;      /* And it's always found */
00065   if (not table->cursor->inited)
00066   {
00067     int error= table->cursor->startIndexScan(idx, 1);
00068     if (error != 0)
00069       return error;
00070   }
00071   /* read_record will be changed to rr_index in rr_index_first */
00072   read_record= rr_index_first;
00073 
00074   return 0;
00075 }
00076 
00077 
00078 int ReadRecord::init_read_record(Session *session_arg,
00079                                  Table *table_arg,
00080                                  optimizer::SqlSelect *select_arg,
00081                                  int use_record_cache,
00082                                  bool print_error_arg)
00083 {
00084   internal::io_cache_st *tempfile;
00085   int error= 0;
00086 
00087   session= session_arg;
00088   table= table_arg;
00089   cursor= table->cursor;
00090   forms= &table;    /* Only one table */
00091 
00092   if (table->sort.addon_field)
00093   {
00094     rec_buf= table->sort.addon_buf;
00095     ref_length= table->sort.addon_length;
00096   }
00097   else
00098   {
00099     table->emptyRecord();
00100     record= table->getInsertRecord();
00101     ref_length= table->cursor->ref_length;
00102   }
00103   select= select_arg;
00104   print_error= print_error_arg;
00105   ignore_not_found_rows= 0;
00106   table->status=0;      /* And it's always found */
00107 
00108   if (select && select->file->inited())
00109   {
00110     tempfile= select->file;
00111   }
00112   else
00113   {
00114     tempfile= table->sort.io_cache;
00115   }
00116 
00117   if (tempfile && tempfile->inited()) // Test if ref-records was used
00118   {
00119     read_record= table->sort.addon_field ? rr_unpack_from_tempfile : rr_from_tempfile;
00120 
00121     io_cache=tempfile;
00122     io_cache->reinit_io_cache(internal::READ_CACHE,0L,0,0);
00123     ref_pos=table->cursor->ref;
00124     if (!table->cursor->inited)
00125     {
00126       error= table->cursor->startTableScan(0);
00127       if (error != 0)
00128         return error;
00129     }
00130 
00131     /*
00132       table->sort.addon_field is checked because if we use addon fields,
00133       it doesn't make sense to use cache - we don't read from the table
00134       and table->sort.io_cache is read sequentially
00135     */
00136     if (!table->sort.addon_field &&
00137         session->variables.read_rnd_buff_size &&
00138         !(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) &&
00139         (table->db_stat & HA_READ_ONLY ||
00140         table->reginfo.lock_type <= TL_READ_NO_INSERT) &&
00141         (uint64_t) table->getShare()->getRecordLength() * (table->cursor->stats.records+
00142                                                 table->cursor->stats.deleted) >
00143         (uint64_t) MIN_FILE_LENGTH_TO_USE_ROW_CACHE &&
00144         io_cache->end_of_file/ref_length * table->getShare()->getRecordLength() >
00145         (internal::my_off_t) MIN_ROWS_TO_USE_TABLE_CACHE &&
00146         !table->getShare()->blob_fields &&
00147         ref_length <= MAX_REFLENGTH)
00148     {
00149       if (init_rr_cache())
00150       {
00151         read_record= rr_from_cache;
00152       }
00153     }
00154   }
00155   else if (select && select->quick)
00156   {
00157     read_record= rr_quick;
00158   }
00159   else if (table->sort.record_pointers)
00160   {
00161     error= table->cursor->startTableScan(0);
00162     if (error != 0)
00163       return error;
00164 
00165     cache_pos=table->sort.record_pointers;
00166     cache_end= cache_pos+ table->sort.found_records * ref_length;
00167     read_record= (table->sort.addon_field ?  rr_unpack_from_buffer : rr_from_pointers);
00168   }
00169   else
00170   {
00171     read_record= rr_sequential;
00172     error= table->cursor->startTableScan(1);
00173     if (error != 0)
00174       return error;
00175 
00176     /* We can use record cache if we don't update dynamic length tables */
00177     if (!table->no_cache &&
00178         (use_record_cache > 0 ||
00179         (int) table->reginfo.lock_type <= (int) TL_READ_WITH_SHARED_LOCKS ||
00180         !(table->getShare()->db_options_in_use & HA_OPTION_PACK_RECORD)))
00181     {
00182       table->cursor->extra_opt(HA_EXTRA_CACHE, session->variables.read_buff_size);
00183     }
00184   }
00185 
00186   return 0;
00187 } /* init_read_record */
00188 
00189 
00190 void ReadRecord::end_read_record()
00191 {                   /* free cache if used */
00192   if (cache)
00193   {
00194     global_read_rnd_buffer.sub(session->variables.read_rnd_buff_size);
00195     free((char*) cache);
00196     cache= NULL;
00197   }
00198   if (table)
00199   {
00200     table->filesort_free_buffers();
00201     (void) cursor->extra(HA_EXTRA_NO_CACHE);
00202     if (read_record != rr_quick) // otherwise quick_range does it
00203       (void) cursor->ha_index_or_rnd_end();
00204 
00205     table= NULL;
00206   }
00207 }
00208 
00209 static int rr_handle_error(ReadRecord *info, int error)
00210 {
00211   if (error == HA_ERR_END_OF_FILE)
00212     error= -1;
00213   else
00214   {
00215     if (info->print_error)
00216       info->table->print_error(error, MYF(0));
00217     if (error < 0)                            // Fix negative BDB errno
00218       error= 1;
00219   }
00220   return error;
00221 }
00222 
00224 static int rr_quick(ReadRecord *info)
00225 {
00226   int tmp;
00227   while ((tmp= info->select->quick->get_next()))
00228   {
00229     if (info->session->getKilled())
00230     {
00231       my_error(ER_SERVER_SHUTDOWN, MYF(0));
00232       return 1;
00233     }
00234     if (tmp != HA_ERR_RECORD_DELETED)
00235     {
00236       tmp= rr_handle_error(info, tmp);
00237       break;
00238     }
00239   }
00240 
00241   return tmp;
00242 }
00243 
00256 static int rr_index_first(ReadRecord *info)
00257 {
00258   int tmp= info->cursor->index_first(info->record);
00259   info->read_record= rr_index;
00260   if (tmp)
00261     tmp= rr_handle_error(info, tmp);
00262   return tmp;
00263 }
00264 
00280 static int rr_index(ReadRecord *info)
00281 {
00282   int tmp= info->cursor->index_next(info->record);
00283   if (tmp)
00284     tmp= rr_handle_error(info, tmp);
00285   return tmp;
00286 }
00287 
00288 int rr_sequential(ReadRecord *info)
00289 {
00290   int tmp;
00291   while ((tmp= info->cursor->rnd_next(info->record)))
00292   {
00293     if (info->session->getKilled())
00294     {
00295       info->session->send_kill_message();
00296       return 1;
00297     }
00298     /*
00299       TODO> Fix this so that engine knows how to behave on its own.
00300       rnd_next can return RECORD_DELETED for MyISAM when one thread is
00301       reading and another deleting without locks.
00302     */
00303     if (tmp != HA_ERR_RECORD_DELETED)
00304     {
00305       tmp= rr_handle_error(info, tmp);
00306       break;
00307     }
00308   }
00309 
00310   return tmp;
00311 }
00312 
00313 static int rr_from_tempfile(ReadRecord *info)
00314 {
00315   int tmp;
00316   for (;;)
00317   {
00318     if (info->io_cache->read(info->ref_pos, info->ref_length))
00319       return -1;          /* End of cursor */
00320     if (!(tmp=info->cursor->rnd_pos(info->record,info->ref_pos)))
00321       break;
00322     /* The following is extremely unlikely to happen */
00323     if (tmp == HA_ERR_RECORD_DELETED ||
00324         (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
00325       continue;
00326     tmp= rr_handle_error(info, tmp);
00327     break;
00328   }
00329   return tmp;
00330 } /* rr_from_tempfile */
00331 
00347 static int rr_unpack_from_tempfile(ReadRecord *info)
00348 {
00349   if (info->io_cache->read(info->rec_buf, info->ref_length))
00350     return -1;
00351   Table *table= info->table;
00352   (*table->sort.unpack)(table->sort.addon_field, info->rec_buf);
00353 
00354   return 0;
00355 }
00356 
00357 static int rr_from_pointers(ReadRecord *info)
00358 {
00359   int tmp;
00360   unsigned char *cache_pos;
00361 
00362 
00363   for (;;)
00364   {
00365     if (info->cache_pos == info->cache_end)
00366       return -1;          /* End of cursor */
00367     cache_pos= info->cache_pos;
00368     info->cache_pos+= info->ref_length;
00369 
00370     if (!(tmp=info->cursor->rnd_pos(info->record,cache_pos)))
00371       break;
00372 
00373     /* The following is extremely unlikely to happen */
00374     if (tmp == HA_ERR_RECORD_DELETED ||
00375         (tmp == HA_ERR_KEY_NOT_FOUND && info->ignore_not_found_rows))
00376       continue;
00377     tmp= rr_handle_error(info, tmp);
00378     break;
00379   }
00380   return tmp;
00381 }
00382 
00398 static int rr_unpack_from_buffer(ReadRecord *info)
00399 {
00400   if (info->cache_pos == info->cache_end)
00401     return -1;                      /* End of buffer */
00402   Table *table= info->table;
00403   (*table->sort.unpack)(table->sort.addon_field, info->cache_pos);
00404   info->cache_pos+= info->ref_length;
00405 
00406   return 0;
00407 }
00408 
00409 /* cacheing of records from a database */
00410 bool ReadRecord::init_rr_cache()
00411 {
00412   uint32_t local_rec_cache_size;
00413 
00414   struct_length= 3 + MAX_REFLENGTH;
00415   reclength= ALIGN_SIZE(table->getShare()->getRecordLength() + 1);
00416   if (reclength < struct_length)
00417     reclength= ALIGN_SIZE(struct_length);
00418 
00419   error_offset= table->getShare()->getRecordLength();
00420   cache_records= (session->variables.read_rnd_buff_size /
00421                         (reclength + struct_length));
00422   local_rec_cache_size= cache_records * reclength;
00423   rec_cache_size= cache_records * ref_length;
00424 
00425   if (not global_read_rnd_buffer.add(session->variables.read_rnd_buff_size))
00426   {
00427     my_error(ER_OUT_OF_GLOBAL_READRNDMEMORY, MYF(ME_ERROR+ME_WAITTANG));
00428     return false;
00429   }
00430 
00431   // We have to allocate one more byte to use uint3korr (see comments for it)
00432   if (cache_records <= 2)
00433     return false;
00434   cache= (unsigned char*) malloc(local_rec_cache_size + cache_records * struct_length + 1);
00435 #ifdef HAVE_VALGRIND
00436   // Avoid warnings in qsort
00437   memset(cache, 0, local_rec_cache_size + cache_records * struct_length + 1);
00438 #endif
00439   read_positions= cache + local_rec_cache_size;
00440   cache_pos= cache_end= cache;
00441 
00442   return true;
00443 } /* init_rr_cache */
00444 
00445 static int rr_from_cache(ReadRecord *info)
00446 {
00447   uint32_t length;
00448   internal::my_off_t rest_of_file;
00449   int16_t error;
00450   unsigned char *position,*ref_position,*record_pos;
00451   uint32_t record;
00452 
00453   for (;;)
00454   {
00455     if (info->cache_pos != info->cache_end)
00456     {
00457       if (info->cache_pos[info->error_offset])
00458       {
00459         shortget(error,info->cache_pos);
00460         if (info->print_error)
00461           info->table->print_error(error,MYF(0));
00462       }
00463       else
00464       {
00465         error=0;
00466         memcpy(info->record,info->cache_pos, (size_t) info->table->getShare()->getRecordLength());
00467       }
00468       info->cache_pos+= info->reclength;
00469       return ((int) error);
00470     }
00471     length=info->rec_cache_size;
00472     rest_of_file= info->io_cache->end_of_file - info->io_cache->tell();
00473     if ((internal::my_off_t) length > rest_of_file)
00474     {
00475       length= (uint32_t) rest_of_file;
00476     }
00477 
00478     if (!length || info->io_cache->read(info->getCache(), length))
00479     {
00480       return -1;      /* End of cursor */
00481     }
00482 
00483     length/=info->ref_length;
00484     position=info->getCache();
00485     ref_position=info->read_positions;
00486     for (uint32_t i= 0 ; i < length ; i++,position+=info->ref_length)
00487     {
00488       memcpy(ref_position,position,(size_t) info->ref_length);
00489       ref_position+=MAX_REFLENGTH;
00490       int3store(ref_position,(long) i);
00491       ref_position+=3;
00492     }
00493     internal::my_qsort(info->read_positions, length, info->struct_length,
00494                        (qsort_cmp) rr_cmp);
00495 
00496     position=info->read_positions;
00497     for (uint32_t i= 0 ; i < length ; i++)
00498     {
00499       memcpy(info->ref_pos, position, (size_t)info->ref_length);
00500       position+=MAX_REFLENGTH;
00501       record=uint3korr(position);
00502       position+=3;
00503       record_pos= info->getCache() + record * info->reclength;
00504       if ((error=(int16_t) info->cursor->rnd_pos(record_pos,info->ref_pos)))
00505       {
00506         record_pos[info->error_offset]=1;
00507         shortstore(record_pos,error);
00508       }
00509       else
00510         record_pos[info->error_offset]=0;
00511     }
00512     info->cache_end= (info->cache_pos= info->getCache())+length*info->reclength;
00513   }
00514 } /* rr_from_cache */
00515 
00516 static int rr_cmp(unsigned char *a,unsigned char *b)
00517 {
00518   if (a[0] != b[0])
00519     return (int) a[0] - (int) b[0];
00520   if (a[1] != b[1])
00521     return (int) a[1] - (int) b[1];
00522   if (a[2] != b[2])
00523     return (int) a[2] - (int) b[2];
00524 #if MAX_REFLENGTH == 4
00525   return (int) a[3] - (int) b[3];
00526 #else
00527   if (a[3] != b[3])
00528     return (int) a[3] - (int) b[3];
00529   if (a[4] != b[4])
00530     return (int) a[4] - (int) b[4];
00531   if (a[5] != b[5])
00532     return (int) a[1] - (int) b[5];
00533   if (a[6] != b[6])
00534     return (int) a[6] - (int) b[6];
00535   return (int) a[7] - (int) b[7];
00536 #endif
00537 }
00538 
00539 } /* namespace drizzled */