-
Olav Sandstaa authored
SMALL READ_RND_BUFFER_SIZE This bug is triggered by setting the system variable read_rnd_buffer_size so low that the created sort buffer used by DS-MRR is too small to fit a single key. When the range scan using DS-MRR starts, it is unable to store any keys in the sort buffer and an uninitialized return value is returned. This return value would have been given its initial value when the first record was read from the index. This causes either a random error value or wrong results from the range scan (zero records). The patch fixes two bugs in the DS-MRR implementation. Bug 1 (the original problem): The cause for this failure is found in DsMrr_impl::choose_mrr_impl(). One of its arguments is the buffer size which is initially specified by read_rnd_buffer_size. Before this is used as argument in the call to get_disk_sweep_mrr_cost() the following is subtracted from the buffer size: table->key_info[keyno].key_length + h->ref_length; The buffer size is stored as an unsigned integer and if it is smaller than the above expression, the result of the subtraction becomes a very large number. When get_disk_sweep_mrr_cost() is called with this huge buffer size, it concludes that there are plenty of room for storing keys in this buffer when it should have concluded that the buffer was too small for storing a single key. This causes the choose_mrr_impl() to return that DS-MRR should be used when it should have returned that the default MRR implementation should have been used due to too small buffer size. The subtraction (the above expression) from the buffer size in DsMrr_impl::choose_mrr_impl() was originally done because an early version of the DsMrr implementation used the sort buffer to store the current position of the scan each time it had filled the sort buffer. This was needed in order to be able to restart the scan next time it should fill the sort buffer. The subtraction was done to count for the space needed for storing the current position. This implementation has since been changed to use a second handler object for scanning the index. With this is place, there was no need for storing the current position in the sort buffer. The code for storing and reading the current scan position to/from the sort buffer has been removed but the reservation of space for it in DsMrr_impl::choose_mrr_impl() has been left in the code. The fix for avoiding that the buffer size is assigned a wrong value is to remove this subtraction. Bug 2: This fix solved the original bug but caused several query plans to wrongly change from using MRR or BKA to not using these. This was caused by a bug in DsMrr_impl::dsmrr_info(). This function first computes the cost for using the default MRR strategy by calling handler::multi_range_read_info(). This takes as one of its arguments a pointer to the buffer size. Since the default MRR implementation does not need a sort buffer, it sets the buffer size to zero. To avoid that this overwrites the original buffer size, a local variable def_bufsz is used in DsMrr_impl::dsmrr_info(). After the call to handler::multi_range_read_info() this will thus always be zero. The bug is that this local variable is used as argument when calling choose_mrr_impl() instead of the original buffer size stored in *bufsz. This causes choose_mrr_impl() to be called with a buffer size of 0 bytes, and as a result it will return that the default MRR implementation should be used (since the zery byte buffer size is too small). The reason this bug has not surfaced earlier is that it has been "hidden" by the first bug. When calling choose_mrr_impl() with a buffer size of 0 the subtraction in choose_mrr_impl() would (wrongly) change this to a very large buffer size that was large enough to use for DS-MRR (or in another way: this second bug sets the supplied buffer size to 0 in DsMrr_impl::dsmrr_info() and then the first bug compensated by changing the 0 byte buffer size to a very large buffer size in choose_mrr_impl()). The fix for this is to replace the bufsz and flags arguments in the call to choose_mrr_impl() to use the original values instead of the values in the local variables def_flags and def_bufsz. After this fix the implementation of DsMrr_impl::dsmrr_info() is similar to the corresponding implementation in DsMrr_impl::dsmrr_info_const().
Olav Sandstaa authoredSMALL READ_RND_BUFFER_SIZE This bug is triggered by setting the system variable read_rnd_buffer_size so low that the created sort buffer used by DS-MRR is too small to fit a single key. When the range scan using DS-MRR starts, it is unable to store any keys in the sort buffer and an uninitialized return value is returned. This return value would have been given its initial value when the first record was read from the index. This causes either a random error value or wrong results from the range scan (zero records). The patch fixes two bugs in the DS-MRR implementation. Bug 1 (the original problem): The cause for this failure is found in DsMrr_impl::choose_mrr_impl(). One of its arguments is the buffer size which is initially specified by read_rnd_buffer_size. Before this is used as argument in the call to get_disk_sweep_mrr_cost() the following is subtracted from the buffer size: table->key_info[keyno].key_length + h->ref_length; The buffer size is stored as an unsigned integer and if it is smaller than the above expression, the result of the subtraction becomes a very large number. When get_disk_sweep_mrr_cost() is called with this huge buffer size, it concludes that there are plenty of room for storing keys in this buffer when it should have concluded that the buffer was too small for storing a single key. This causes the choose_mrr_impl() to return that DS-MRR should be used when it should have returned that the default MRR implementation should have been used due to too small buffer size. The subtraction (the above expression) from the buffer size in DsMrr_impl::choose_mrr_impl() was originally done because an early version of the DsMrr implementation used the sort buffer to store the current position of the scan each time it had filled the sort buffer. This was needed in order to be able to restart the scan next time it should fill the sort buffer. The subtraction was done to count for the space needed for storing the current position. This implementation has since been changed to use a second handler object for scanning the index. With this is place, there was no need for storing the current position in the sort buffer. The code for storing and reading the current scan position to/from the sort buffer has been removed but the reservation of space for it in DsMrr_impl::choose_mrr_impl() has been left in the code. The fix for avoiding that the buffer size is assigned a wrong value is to remove this subtraction. Bug 2: This fix solved the original bug but caused several query plans to wrongly change from using MRR or BKA to not using these. This was caused by a bug in DsMrr_impl::dsmrr_info(). This function first computes the cost for using the default MRR strategy by calling handler::multi_range_read_info(). This takes as one of its arguments a pointer to the buffer size. Since the default MRR implementation does not need a sort buffer, it sets the buffer size to zero. To avoid that this overwrites the original buffer size, a local variable def_bufsz is used in DsMrr_impl::dsmrr_info(). After the call to handler::multi_range_read_info() this will thus always be zero. The bug is that this local variable is used as argument when calling choose_mrr_impl() instead of the original buffer size stored in *bufsz. This causes choose_mrr_impl() to be called with a buffer size of 0 bytes, and as a result it will return that the default MRR implementation should be used (since the zery byte buffer size is too small). The reason this bug has not surfaced earlier is that it has been "hidden" by the first bug. When calling choose_mrr_impl() with a buffer size of 0 the subtraction in choose_mrr_impl() would (wrongly) change this to a very large buffer size that was large enough to use for DS-MRR (or in another way: this second bug sets the supplied buffer size to 0 in DsMrr_impl::dsmrr_info() and then the first bug compensated by changing the 0 byte buffer size to a very large buffer size in choose_mrr_impl()). The fix for this is to replace the bufsz and flags arguments in the call to choose_mrr_impl() to use the original values instead of the values in the local variables def_flags and def_bufsz. After this fix the implementation of DsMrr_impl::dsmrr_info() is similar to the corresponding implementation in DsMrr_impl::dsmrr_info_const().
Loading