Loading include/my_base.h +17 −0 Original line number Diff line number Diff line Loading @@ -376,6 +376,15 @@ enum data_file_type { /* For key ranges */ #define NO_MIN_RANGE 1 #define NO_MAX_RANGE 2 #define NEAR_MIN 4 #define NEAR_MAX 8 #define UNIQUE_RANGE 16 #define EQ_RANGE 32 #define NULL_RANGE 64 #define GEOM_FLAG 128 typedef struct st_key_range { const byte *key; Loading @@ -383,6 +392,14 @@ typedef struct st_key_range enum ha_rkey_function flag; } key_range; typedef struct st_key_multi_range { key_range start_key; key_range end_key; char *ptr; /* Free to use by caller (ptr to row etc) */ uint range_flag; /* key range flags see above */ } KEY_MULTI_RANGE; /* For number of records */ #ifdef BIG_TABLES Loading sql/handler.cc +125 −0 Original line number Diff line number Diff line Loading @@ -1786,6 +1786,131 @@ int ha_table_exists(THD* thd, const char* db, const char* name) #endif /* Read the first row of a multi-range set. SYNOPSIS read_multi_range_first() found_range_p Returns a pointer to the element in 'ranges' that corresponds to the returned row. ranges An array of KEY_MULTI_RANGE range descriptions. range_count Number of ranges in 'ranges'. sorted If result should be sorted per key. buffer A HANDLER_BUFFER for internal handler usage. NOTES Record is read into table->record[0]. *found_range_p returns a valid value only if read_multi_range_first() returns 0. Sorting is done within each range. If you want an overall sort, enter 'ranges' with sorted ranges. RETURN 0 OK, found a row HA_ERR_END_OF_FILE No rows in range # Error code */ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer) { int result= HA_ERR_END_OF_FILE; DBUG_ENTER("handler::read_multi_range_first"); multi_range_sorted= sorted; multi_range_buffer= buffer; for (multi_range_curr= ranges, multi_range_end= ranges + range_count; multi_range_curr < multi_range_end; multi_range_curr++) { result= read_range_first(multi_range_curr->start_key.length ? &multi_range_curr->start_key : 0, multi_range_curr->end_key.length ? &multi_range_curr->end_key : 0, test(multi_range_curr->range_flag & EQ_RANGE), multi_range_sorted); if (result != HA_ERR_END_OF_FILE) break; } *found_range_p= multi_range_curr; DBUG_PRINT("exit",("result %d", result)); DBUG_RETURN(result); } /* Read the next row of a multi-range set. SYNOPSIS read_multi_range_next() found_range_p Returns a pointer to the element in 'ranges' that corresponds to the returned row. NOTES Record is read into table->record[0]. *found_range_p returns a valid value only if read_multi_range_next() returns 0. RETURN 0 OK, found a row HA_ERR_END_OF_FILE No (more) rows in range # Error code */ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) { int result; DBUG_ENTER("handler::read_multi_range_next"); /* We should not be called after the last call returned EOF. */ DBUG_ASSERT(multi_range_curr < multi_range_end); do { /* Save a call if there can be only one row in range. */ if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE)) { result= read_range_next(); /* On success or non-EOF errors jump to the end. */ if (result != HA_ERR_END_OF_FILE) break; } else { /* We need to set this for the last range only, but checking this condition is more expensive than just setting the result code. */ result= HA_ERR_END_OF_FILE; } /* Try the next range(s) until one matches a record. */ for (multi_range_curr++; multi_range_curr < multi_range_end; multi_range_curr++) { result= read_range_first(multi_range_curr->start_key.length ? &multi_range_curr->start_key : 0, multi_range_curr->end_key.length ? &multi_range_curr->end_key : 0, test(multi_range_curr->range_flag & EQ_RANGE), multi_range_sorted); if (result != HA_ERR_END_OF_FILE) break; } } while ((result == HA_ERR_END_OF_FILE) && (multi_range_curr < multi_range_end)); *found_range_p= multi_range_curr; DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result)); DBUG_RETURN(result); } /* Read first row between two ranges. Store ranges for future calls to read_range_next Loading sql/handler.h +26 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ #define HA_FILE_BASED (1 << 26) #define HA_NO_VARCHAR (1 << 27) #define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */ #define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */ /* bits in index_flags(index_number) for what you can do with index */ Loading Loading @@ -276,6 +277,21 @@ typedef struct st_ha_check_opt } HA_CHECK_OPT; /* This is a buffer area that the handler can use to store rows. 'end_of_used_area' should be kept updated after calls to read-functions so that other parts of the code can use the remaining area (until next read calls is issued). */ typedef struct st_handler_buffer { const byte *buffer; /* Buffer one can start using */ const byte *buffer_end; /* End of buffer */ byte *end_of_used_area; /* End of area that was used by handler */ } HANDLER_BUFFER; class handler :public Sql_alloc { protected: Loading Loading @@ -310,6 +326,12 @@ class handler :public Sql_alloc time_t check_time; time_t update_time; /* The following are for read_multi_range */ bool multi_range_sorted; KEY_MULTI_RANGE *multi_range_curr; KEY_MULTI_RANGE *multi_range_end; HANDLER_BUFFER *multi_range_buffer; /* The following are for read_range() */ key_range save_end_range, *end_range; KEY_PART_INFO *range_key_part; Loading Loading @@ -421,6 +443,10 @@ class handler :public Sql_alloc virtual int index_next_same(byte *buf, const byte *key, uint keylen); virtual int index_read_last(byte * buf, const byte * key, uint key_len) { return (my_errno=HA_ERR_WRONG_COMMAND); } virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer); virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p); virtual int read_range_first(const key_range *start_key, const key_range *end_key, bool eq_range, bool sorted); Loading sql/mysqld.cc +6 −1 Original line number Diff line number Diff line Loading @@ -4143,7 +4143,7 @@ enum options_mysqld OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE, OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, Loading Loading @@ -5139,6 +5139,11 @@ The minimum value for this variable is 4096.", "After this many write locks, allow some read locks to run in between.", (gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, {"multi_range_count", OPT_MULTI_RANGE_COUNT, "Number of key ranges to request at once.", (gptr*) &global_system_variables.multi_range_count, (gptr*) &max_system_variables.multi_range_count, 0, GET_ULONG, REQUIRED_ARG, 256, 1, ~0L, 0, 1, 0}, {"myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "Block size to be used for MyISAM index pages.", (gptr*) &opt_myisam_block_size, Loading sql/opt_range.cc +188 −55 Original line number Diff line number Diff line Loading @@ -712,7 +712,7 @@ QUICK_SELECT_I::QUICK_SELECT_I() QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc, MEM_ROOT *parent_alloc) :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0) :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0),in_range(0) { sorted= 0; index= key_nr; Loading @@ -720,6 +720,13 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, key_part_info= head->key_info[index].key_part; my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); /* 'thd' is not accessible in QUICK_RANGE_SELECT::get_next_init(). */ multi_range_bufsiz= thd->variables.read_rnd_buff_size; multi_range_count= thd->variables.multi_range_count; multi_range_length= 0; multi_range= NULL; multi_range_buff= NULL; if (!no_alloc && !parent_alloc) { // Allocates everything through the internal memroot Loading @@ -736,6 +743,10 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, int QUICK_RANGE_SELECT::init() { DBUG_ENTER("QUICK_RANGE_SELECT::init"); if ((error= get_next_init())) DBUG_RETURN(error); if (file->inited == handler::NONE) DBUG_RETURN(error= file->ha_index_init(index)); error= 0; Loading Loading @@ -771,6 +782,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() delete_dynamic(&ranges); /* ranges are allocated in alloc */ free_root(&alloc,MYF(0)); } if (multi_range) my_free((char*) multi_range, MYF(0)); if (multi_range_buff) my_free((char*) multi_range_buff, MYF(0)); DBUG_VOID_RETURN; } Loading Loading @@ -5872,58 +5887,178 @@ int QUICK_ROR_UNION_SELECT::get_next() DBUG_RETURN(error); } /* get next possible record using quick-struct */ /* Initialize data structures needed by get_next(). SYNOPSIS QUICK_RANGE_SELECT::get_next_init() DESCRIPTION This is called from get_next() at its first call for an object. It allocates memory buffers and sets size variables. RETURN 0 OK. != 0 Error. */ int QUICK_RANGE_SELECT::get_next_init(void) { uint mrange_bufsiz; byte *mrange_buff; DBUG_ENTER("QUICK_RANGE_SELECT::get_next_init"); /* Do not allocate the buffers twice. */ if (multi_range_length) { DBUG_ASSERT(multi_range_length == min(multi_range_count, ranges.elements)); DBUG_RETURN(0); } /* If the ranges are not yet initialized, wait for the next call. */ if (! ranges.elements) { DBUG_RETURN(0); } /* Allocate the ranges array. */ multi_range_length= min(multi_range_count, ranges.elements); DBUG_ASSERT(multi_range_length > 0); while (multi_range_length && ! (multi_range= (KEY_MULTI_RANGE*) my_malloc(multi_range_length * sizeof(KEY_MULTI_RANGE), MYF(MY_WME)))) { /* Try to shrink the buffers until it is 0. */ multi_range_length/= 2; } if (! multi_range) { multi_range_length= 0; DBUG_RETURN(HA_ERR_OUT_OF_MEM); } /* Allocate the handler buffer if necessary. */ if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER) { mrange_bufsiz= min(multi_range_bufsiz, QUICK_SELECT_I::records * head->reclength); while (mrange_bufsiz && ! my_multi_malloc(MYF(MY_WME), &multi_range_buff, sizeof(*multi_range_buff), &mrange_buff, mrange_bufsiz, NullS)) { /* Try to shrink the buffers until both are 0. */ mrange_bufsiz/= 2; } if (! multi_range_buff) { my_free((char*) multi_range, MYF(0)); multi_range= NULL; multi_range_length= 0; DBUG_RETURN(HA_ERR_OUT_OF_MEM); } /* Initialize the handler buffer. */ multi_range_buff->buffer= mrange_buff; multi_range_buff->buffer_end= mrange_buff + mrange_bufsiz; multi_range_buff->end_of_used_area= mrange_buff; } /* Initialize the current QUICK_RANGE pointer. */ cur_range= (QUICK_RANGE**) ranges.buffer; DBUG_RETURN(0); } /* Get next possible record using quick-struct. SYNOPSIS QUICK_RANGE_SELECT::get_next() NOTES Record is read into table->record[0] RETURN 0 Found row HA_ERR_END_OF_FILE No (more) rows in range # Error code */ int QUICK_RANGE_SELECT::get_next() { int result; KEY_MULTI_RANGE *mrange; key_range *start_key; key_range *end_key; DBUG_ENTER("QUICK_RANGE_SELECT::get_next"); DBUG_ASSERT(multi_range_length && multi_range && (cur_range >= (QUICK_RANGE**) ranges.buffer) && (cur_range <= (QUICK_RANGE**) ranges.buffer + ranges.elements)); for (;;) { int result; key_range start_key, end_key; if (range) if (in_range) { // Already read through key result= file->read_range_next(); /* We did already start to read this key. */ result= file->read_multi_range_next(&mrange); if (result != HA_ERR_END_OF_FILE) { in_range= ! result; DBUG_RETURN(result); } } if (!cur_range) range= *(cur_range= (QUICK_RANGE**) ranges.buffer); else range= (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? (QUICK_RANGE*) 0 : *(++cur_range); if (!range) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used uint count= min(multi_range_length, ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer)); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ in_range= FALSE; DBUG_RETURN(HA_ERR_END_OF_FILE); } KEY_MULTI_RANGE *mrange_slot, *mrange_end; for (mrange_slot= multi_range, mrange_end= mrange_slot+count; mrange_slot < mrange_end; mrange_slot++) { start_key= &mrange_slot->start_key; end_key= &mrange_slot->end_key; range= *(cur_range++); start_key.key= (const byte*) range->min_key; start_key.length= range->min_length; start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : start_key->key= (const byte*) range->min_key; start_key->length= range->min_length; start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : (range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); end_key.key= (const byte*) range->max_key; end_key.length= range->max_length; end_key->key= (const byte*) range->max_key; end_key->length= range->max_length; /* We use READ_AFTER_KEY here because if we are reading on a key prefix we want to find all keys with this prefix We use HA_READ_AFTER_KEY here because if we are reading on a key prefix. We want to find all keys with this prefix. */ end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); result= file->read_range_first(range->min_length ? &start_key : 0, range->max_length ? &end_key : 0, test(range->flag & EQ_RANGE), sorted); if (range->flag == (UNIQUE_RANGE | EQ_RANGE)) range=0; // Stop searching mrange_slot->range_flag= range->flag; } result= file->read_multi_range_first(&mrange, multi_range, count, sorted, multi_range_buff); if (result != HA_ERR_END_OF_FILE) { in_range= ! result; DBUG_RETURN(result); range=0; // No matching rows; go to next range } in_range= FALSE; /* No matching rows; go to next set of ranges. */ } } Loading Loading @@ -5974,15 +6109,14 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) DBUG_RETURN(result); } if (!cur_range) range= *(cur_range= (QUICK_RANGE**) ranges.buffer); /* First range. */ else range= (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? (QUICK_RANGE*) 0 : *(++cur_range); /* Next range. */ if (!range) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ range= 0; DBUG_RETURN(HA_ERR_END_OF_FILE); } range= *(cur_range++); start_key.key= (const byte*) range->min_key; start_key.length= min(range->min_length, prefix_length); Loading Loading @@ -6030,15 +6164,14 @@ int QUICK_RANGE_SELECT_GEOM::get_next() DBUG_RETURN(result); } if (!cur_range) range= *(cur_range= (QUICK_RANGE**) ranges.buffer); else range= (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? (QUICK_RANGE*) 0 : *(++cur_range); if (!range) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ range= 0; DBUG_RETURN(HA_ERR_END_OF_FILE); } range= *(cur_range++); result= file->index_read(record, (byte*) range->min_key, Loading Loading
include/my_base.h +17 −0 Original line number Diff line number Diff line Loading @@ -376,6 +376,15 @@ enum data_file_type { /* For key ranges */ #define NO_MIN_RANGE 1 #define NO_MAX_RANGE 2 #define NEAR_MIN 4 #define NEAR_MAX 8 #define UNIQUE_RANGE 16 #define EQ_RANGE 32 #define NULL_RANGE 64 #define GEOM_FLAG 128 typedef struct st_key_range { const byte *key; Loading @@ -383,6 +392,14 @@ typedef struct st_key_range enum ha_rkey_function flag; } key_range; typedef struct st_key_multi_range { key_range start_key; key_range end_key; char *ptr; /* Free to use by caller (ptr to row etc) */ uint range_flag; /* key range flags see above */ } KEY_MULTI_RANGE; /* For number of records */ #ifdef BIG_TABLES Loading
sql/handler.cc +125 −0 Original line number Diff line number Diff line Loading @@ -1786,6 +1786,131 @@ int ha_table_exists(THD* thd, const char* db, const char* name) #endif /* Read the first row of a multi-range set. SYNOPSIS read_multi_range_first() found_range_p Returns a pointer to the element in 'ranges' that corresponds to the returned row. ranges An array of KEY_MULTI_RANGE range descriptions. range_count Number of ranges in 'ranges'. sorted If result should be sorted per key. buffer A HANDLER_BUFFER for internal handler usage. NOTES Record is read into table->record[0]. *found_range_p returns a valid value only if read_multi_range_first() returns 0. Sorting is done within each range. If you want an overall sort, enter 'ranges' with sorted ranges. RETURN 0 OK, found a row HA_ERR_END_OF_FILE No rows in range # Error code */ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer) { int result= HA_ERR_END_OF_FILE; DBUG_ENTER("handler::read_multi_range_first"); multi_range_sorted= sorted; multi_range_buffer= buffer; for (multi_range_curr= ranges, multi_range_end= ranges + range_count; multi_range_curr < multi_range_end; multi_range_curr++) { result= read_range_first(multi_range_curr->start_key.length ? &multi_range_curr->start_key : 0, multi_range_curr->end_key.length ? &multi_range_curr->end_key : 0, test(multi_range_curr->range_flag & EQ_RANGE), multi_range_sorted); if (result != HA_ERR_END_OF_FILE) break; } *found_range_p= multi_range_curr; DBUG_PRINT("exit",("result %d", result)); DBUG_RETURN(result); } /* Read the next row of a multi-range set. SYNOPSIS read_multi_range_next() found_range_p Returns a pointer to the element in 'ranges' that corresponds to the returned row. NOTES Record is read into table->record[0]. *found_range_p returns a valid value only if read_multi_range_next() returns 0. RETURN 0 OK, found a row HA_ERR_END_OF_FILE No (more) rows in range # Error code */ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p) { int result; DBUG_ENTER("handler::read_multi_range_next"); /* We should not be called after the last call returned EOF. */ DBUG_ASSERT(multi_range_curr < multi_range_end); do { /* Save a call if there can be only one row in range. */ if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE)) { result= read_range_next(); /* On success or non-EOF errors jump to the end. */ if (result != HA_ERR_END_OF_FILE) break; } else { /* We need to set this for the last range only, but checking this condition is more expensive than just setting the result code. */ result= HA_ERR_END_OF_FILE; } /* Try the next range(s) until one matches a record. */ for (multi_range_curr++; multi_range_curr < multi_range_end; multi_range_curr++) { result= read_range_first(multi_range_curr->start_key.length ? &multi_range_curr->start_key : 0, multi_range_curr->end_key.length ? &multi_range_curr->end_key : 0, test(multi_range_curr->range_flag & EQ_RANGE), multi_range_sorted); if (result != HA_ERR_END_OF_FILE) break; } } while ((result == HA_ERR_END_OF_FILE) && (multi_range_curr < multi_range_end)); *found_range_p= multi_range_curr; DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result)); DBUG_RETURN(result); } /* Read first row between two ranges. Store ranges for future calls to read_range_next Loading
sql/handler.h +26 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ #define HA_FILE_BASED (1 << 26) #define HA_NO_VARCHAR (1 << 27) #define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */ #define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */ /* bits in index_flags(index_number) for what you can do with index */ Loading Loading @@ -276,6 +277,21 @@ typedef struct st_ha_check_opt } HA_CHECK_OPT; /* This is a buffer area that the handler can use to store rows. 'end_of_used_area' should be kept updated after calls to read-functions so that other parts of the code can use the remaining area (until next read calls is issued). */ typedef struct st_handler_buffer { const byte *buffer; /* Buffer one can start using */ const byte *buffer_end; /* End of buffer */ byte *end_of_used_area; /* End of area that was used by handler */ } HANDLER_BUFFER; class handler :public Sql_alloc { protected: Loading Loading @@ -310,6 +326,12 @@ class handler :public Sql_alloc time_t check_time; time_t update_time; /* The following are for read_multi_range */ bool multi_range_sorted; KEY_MULTI_RANGE *multi_range_curr; KEY_MULTI_RANGE *multi_range_end; HANDLER_BUFFER *multi_range_buffer; /* The following are for read_range() */ key_range save_end_range, *end_range; KEY_PART_INFO *range_key_part; Loading Loading @@ -421,6 +443,10 @@ class handler :public Sql_alloc virtual int index_next_same(byte *buf, const byte *key, uint keylen); virtual int index_read_last(byte * buf, const byte * key, uint key_len) { return (my_errno=HA_ERR_WRONG_COMMAND); } virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p, KEY_MULTI_RANGE *ranges, uint range_count, bool sorted, HANDLER_BUFFER *buffer); virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p); virtual int read_range_first(const key_range *start_key, const key_range *end_key, bool eq_range, bool sorted); Loading
sql/mysqld.cc +6 −1 Original line number Diff line number Diff line Loading @@ -4143,7 +4143,7 @@ enum options_mysqld OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE, OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, Loading Loading @@ -5139,6 +5139,11 @@ The minimum value for this variable is 4096.", "After this many write locks, allow some read locks to run in between.", (gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, {"multi_range_count", OPT_MULTI_RANGE_COUNT, "Number of key ranges to request at once.", (gptr*) &global_system_variables.multi_range_count, (gptr*) &max_system_variables.multi_range_count, 0, GET_ULONG, REQUIRED_ARG, 256, 1, ~0L, 0, 1, 0}, {"myisam_block_size", OPT_MYISAM_BLOCK_SIZE, "Block size to be used for MyISAM index pages.", (gptr*) &opt_myisam_block_size, Loading
sql/opt_range.cc +188 −55 Original line number Diff line number Diff line Loading @@ -712,7 +712,7 @@ QUICK_SELECT_I::QUICK_SELECT_I() QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc, MEM_ROOT *parent_alloc) :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0) :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0),in_range(0) { sorted= 0; index= key_nr; Loading @@ -720,6 +720,13 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, key_part_info= head->key_info[index].key_part; my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); /* 'thd' is not accessible in QUICK_RANGE_SELECT::get_next_init(). */ multi_range_bufsiz= thd->variables.read_rnd_buff_size; multi_range_count= thd->variables.multi_range_count; multi_range_length= 0; multi_range= NULL; multi_range_buff= NULL; if (!no_alloc && !parent_alloc) { // Allocates everything through the internal memroot Loading @@ -736,6 +743,10 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, int QUICK_RANGE_SELECT::init() { DBUG_ENTER("QUICK_RANGE_SELECT::init"); if ((error= get_next_init())) DBUG_RETURN(error); if (file->inited == handler::NONE) DBUG_RETURN(error= file->ha_index_init(index)); error= 0; Loading Loading @@ -771,6 +782,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() delete_dynamic(&ranges); /* ranges are allocated in alloc */ free_root(&alloc,MYF(0)); } if (multi_range) my_free((char*) multi_range, MYF(0)); if (multi_range_buff) my_free((char*) multi_range_buff, MYF(0)); DBUG_VOID_RETURN; } Loading Loading @@ -5872,58 +5887,178 @@ int QUICK_ROR_UNION_SELECT::get_next() DBUG_RETURN(error); } /* get next possible record using quick-struct */ /* Initialize data structures needed by get_next(). SYNOPSIS QUICK_RANGE_SELECT::get_next_init() DESCRIPTION This is called from get_next() at its first call for an object. It allocates memory buffers and sets size variables. RETURN 0 OK. != 0 Error. */ int QUICK_RANGE_SELECT::get_next_init(void) { uint mrange_bufsiz; byte *mrange_buff; DBUG_ENTER("QUICK_RANGE_SELECT::get_next_init"); /* Do not allocate the buffers twice. */ if (multi_range_length) { DBUG_ASSERT(multi_range_length == min(multi_range_count, ranges.elements)); DBUG_RETURN(0); } /* If the ranges are not yet initialized, wait for the next call. */ if (! ranges.elements) { DBUG_RETURN(0); } /* Allocate the ranges array. */ multi_range_length= min(multi_range_count, ranges.elements); DBUG_ASSERT(multi_range_length > 0); while (multi_range_length && ! (multi_range= (KEY_MULTI_RANGE*) my_malloc(multi_range_length * sizeof(KEY_MULTI_RANGE), MYF(MY_WME)))) { /* Try to shrink the buffers until it is 0. */ multi_range_length/= 2; } if (! multi_range) { multi_range_length= 0; DBUG_RETURN(HA_ERR_OUT_OF_MEM); } /* Allocate the handler buffer if necessary. */ if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER) { mrange_bufsiz= min(multi_range_bufsiz, QUICK_SELECT_I::records * head->reclength); while (mrange_bufsiz && ! my_multi_malloc(MYF(MY_WME), &multi_range_buff, sizeof(*multi_range_buff), &mrange_buff, mrange_bufsiz, NullS)) { /* Try to shrink the buffers until both are 0. */ mrange_bufsiz/= 2; } if (! multi_range_buff) { my_free((char*) multi_range, MYF(0)); multi_range= NULL; multi_range_length= 0; DBUG_RETURN(HA_ERR_OUT_OF_MEM); } /* Initialize the handler buffer. */ multi_range_buff->buffer= mrange_buff; multi_range_buff->buffer_end= mrange_buff + mrange_bufsiz; multi_range_buff->end_of_used_area= mrange_buff; } /* Initialize the current QUICK_RANGE pointer. */ cur_range= (QUICK_RANGE**) ranges.buffer; DBUG_RETURN(0); } /* Get next possible record using quick-struct. SYNOPSIS QUICK_RANGE_SELECT::get_next() NOTES Record is read into table->record[0] RETURN 0 Found row HA_ERR_END_OF_FILE No (more) rows in range # Error code */ int QUICK_RANGE_SELECT::get_next() { int result; KEY_MULTI_RANGE *mrange; key_range *start_key; key_range *end_key; DBUG_ENTER("QUICK_RANGE_SELECT::get_next"); DBUG_ASSERT(multi_range_length && multi_range && (cur_range >= (QUICK_RANGE**) ranges.buffer) && (cur_range <= (QUICK_RANGE**) ranges.buffer + ranges.elements)); for (;;) { int result; key_range start_key, end_key; if (range) if (in_range) { // Already read through key result= file->read_range_next(); /* We did already start to read this key. */ result= file->read_multi_range_next(&mrange); if (result != HA_ERR_END_OF_FILE) { in_range= ! result; DBUG_RETURN(result); } } if (!cur_range) range= *(cur_range= (QUICK_RANGE**) ranges.buffer); else range= (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? (QUICK_RANGE*) 0 : *(++cur_range); if (!range) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used uint count= min(multi_range_length, ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer)); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ in_range= FALSE; DBUG_RETURN(HA_ERR_END_OF_FILE); } KEY_MULTI_RANGE *mrange_slot, *mrange_end; for (mrange_slot= multi_range, mrange_end= mrange_slot+count; mrange_slot < mrange_end; mrange_slot++) { start_key= &mrange_slot->start_key; end_key= &mrange_slot->end_key; range= *(cur_range++); start_key.key= (const byte*) range->min_key; start_key.length= range->min_length; start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : start_key->key= (const byte*) range->min_key; start_key->length= range->min_length; start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : (range->flag & EQ_RANGE) ? HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); end_key.key= (const byte*) range->max_key; end_key.length= range->max_length; end_key->key= (const byte*) range->max_key; end_key->length= range->max_length; /* We use READ_AFTER_KEY here because if we are reading on a key prefix we want to find all keys with this prefix We use HA_READ_AFTER_KEY here because if we are reading on a key prefix. We want to find all keys with this prefix. */ end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY); result= file->read_range_first(range->min_length ? &start_key : 0, range->max_length ? &end_key : 0, test(range->flag & EQ_RANGE), sorted); if (range->flag == (UNIQUE_RANGE | EQ_RANGE)) range=0; // Stop searching mrange_slot->range_flag= range->flag; } result= file->read_multi_range_first(&mrange, multi_range, count, sorted, multi_range_buff); if (result != HA_ERR_END_OF_FILE) { in_range= ! result; DBUG_RETURN(result); range=0; // No matching rows; go to next range } in_range= FALSE; /* No matching rows; go to next set of ranges. */ } } Loading Loading @@ -5974,15 +6109,14 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) DBUG_RETURN(result); } if (!cur_range) range= *(cur_range= (QUICK_RANGE**) ranges.buffer); /* First range. */ else range= (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? (QUICK_RANGE*) 0 : *(++cur_range); /* Next range. */ if (!range) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ range= 0; DBUG_RETURN(HA_ERR_END_OF_FILE); } range= *(cur_range++); start_key.key= (const byte*) range->min_key; start_key.length= min(range->min_length, prefix_length); Loading Loading @@ -6030,15 +6164,14 @@ int QUICK_RANGE_SELECT_GEOM::get_next() DBUG_RETURN(result); } if (!cur_range) range= *(cur_range= (QUICK_RANGE**) ranges.buffer); else range= (cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? (QUICK_RANGE*) 0 : *(++cur_range); if (!range) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer); if (count == 0) { /* Ranges have already been used up before. None is left for read. */ range= 0; DBUG_RETURN(HA_ERR_END_OF_FILE); } range= *(cur_range++); result= file->index_read(record, (byte*) range->min_key, Loading