Optimize performance of my_bitmap

MDEV-33502 Slowdown when running nested statement with many partitions

This change was triggered to help some MariaDB users with close to
10000 bits in their bitmaps.

- Change underlaying storage to be 64 bit instead of 32bit.
  - This reduses number of loops to scan bitmaps.
  - This can cause some bitmaps to be 4 byte large.
- Ensure that all not used top-bits are always 0 (simplifes code as
  the last 64 bit storage is not a special case anymore).
- Use my_find_first_bit() to find the first set bit which is much faster
  than scanning trough things byte by byte and then bit by bit.

Other things:
- Added a bool to remember if my_bitmap_init() did allocate the bitmap
  array. my_bitmap_free() will only free arrays it did allocate.
  This allowed me to remove setting 'bitmap=0' before calling
  my_bitmap_free() for cases where the bitmap's where allocated externally.
- my_bitmap_init() sets bitmap to 0 in case of failure.
- Added 'universal' asserts to most bitmap functions.
- Change all remaining calls to bitmap_init() to my_bitmap_init().
  - To finish the change from 2014.
- Changed all usage of uint32 in my_bitmap.h to my_bitmap_map.
- Updated bitmap_copy() to handle bitmaps of different size.
- Removed const from bitmap_exists_intersection() as this caused casts
  on all usage.
- Removed not used function bitmap_set_above().
- Renamed create_last_word_mask() to create_last_bit_mask() (to match
  name changes in my_bitmap.cc)
- Extended bitmap-t with test for more bitmap functions.
This commit is contained in:
Monty 2024-02-18 17:30:01 +02:00
parent d4e1731fbc
commit b5d65fc105
18 changed files with 452 additions and 397 deletions

View File

@ -22,7 +22,7 @@
#include <m_string.h>
#include <my_pthread.h>
typedef uint32 my_bitmap_map;
typedef ulonglong my_bitmap_map;
typedef struct st_bitmap
{
@ -34,21 +34,19 @@ typedef struct st_bitmap
acquiring the mutex
*/
mysql_mutex_t *mutex;
my_bitmap_map last_word_mask;
my_bitmap_map last_bit_mask;
uint32 n_bits; /* number of bits occupied by the above */
my_bool bitmap_allocated;
} MY_BITMAP;
#ifdef __cplusplus
extern "C" {
#endif
/* compatibility functions */
#define bitmap_init(A,B,C,D) my_bitmap_init(A,B,C,D)
#define bitmap_free(A) my_bitmap_free(A)
/* Reset memory. Faster then doing a full bzero */
#define my_bitmap_clear(A) ((A)->bitmap= 0)
extern void create_last_word_mask(MY_BITMAP *map);
extern void create_last_bit_mask(MY_BITMAP *map);
extern my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
my_bool thread_safe);
extern my_bool bitmap_is_clear_all(const MY_BITMAP *map);
@ -63,12 +61,12 @@ extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_union_is_set_all(const MY_BITMAP *map1,
const MY_BITMAP *map2);
extern my_bool bitmap_exists_intersection(const MY_BITMAP **bitmap_array,
extern my_bool bitmap_exists_intersection(MY_BITMAP **bitmap_array,
uint bitmap_count,
uint start_bit, uint end_bit);
extern uint bitmap_set_next(MY_BITMAP *map);
extern uint bitmap_get_first(const MY_BITMAP *map);
extern uint bitmap_get_first_clear(const MY_BITMAP *map);
extern uint bitmap_get_first_set(const MY_BITMAP *map);
extern uint bitmap_bits_set(const MY_BITMAP *map);
extern uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit);
@ -84,12 +82,16 @@ extern void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2);
extern uint bitmap_lock_set_next(MY_BITMAP *map);
extern void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit);
/* Fast, not thread safe, bitmap functions */
#define bitmap_buffer_size(bits) (((bits)+31)/32)*4
#define my_bitmap_map_bytes sizeof(my_bitmap_map)
#define my_bitmap_map_bits (my_bitmap_map_bytes*8)
#define bitmap_buffer_size(bits) (MY_ALIGN(bits, my_bitmap_map_bits)*my_bitmap_map_bytes)
#define no_bytes_in_map(map) (((map)->n_bits + 7)/8)
#define no_words_in_map(map) (((map)->n_bits + 31)/32)
#define bytes_word_aligned(bytes) (4*((bytes + 3)/4))
/* The following functions must be compatible with create_last_word_mask()! */
#define no_words_in_map(map) (((map)->n_bits + (my_bitmap_map_bits-1))/my_bitmap_map_bits)
#define bytes_word_aligned(bytes) (8*((bytes + 7)/8))
/* Fast, not thread safe, bitmap functions */
/* The following functions must be compatible with create_last_bit_mask()! */
static inline void
bitmap_set_bit(MY_BITMAP *map,uint bit)
{
@ -119,18 +121,26 @@ bitmap_is_set(const MY_BITMAP *map,uint bit)
return !!(*b & (1U << (bit & 7)));
}
/* Return true if bitmaps are equal */
static inline my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
if (memcmp(map1->bitmap, map2->bitmap, 4*(no_words_in_map(map1)-1)) != 0)
return FALSE;
return ((*map1->last_word_ptr | map1->last_word_mask) ==
(*map2->last_word_ptr | map2->last_word_mask));
DBUG_ASSERT(map1->n_bits == map2->n_bits);
return (memcmp(map1->bitmap, map2->bitmap, 8*(no_words_in_map(map1))) == 0);
}
#define bitmap_clear_all(MAP) \
{ memset((MAP)->bitmap, 0, 4*no_words_in_map((MAP))); }
#define bitmap_set_all(MAP) \
(memset((MAP)->bitmap, 0xFF, 4*no_words_in_map((MAP))))
{ memset((MAP)->bitmap, 0, 8*no_words_in_map((MAP))); }
static inline void
bitmap_set_all(const MY_BITMAP *map)
{
if (map->n_bits)
{
memset(map->bitmap, 0xFF, 8*(no_words_in_map(map)-1));
DBUG_ASSERT(map->bitmap + no_words_in_map(map)-1 == map->last_word_ptr);
*map->last_word_ptr= ~map->last_bit_mask;
}
}
#ifdef __cplusplus
}

View File

@ -13,7 +13,9 @@
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335
USA
*/
/*
Handling of uchar arrays as large bitmaps.
@ -21,9 +23,18 @@
API limitations (or, rather asserted safety assumptions,
to encourage correct programming)
* the internal size is a set of 32 bit words
* the internal storage is a set of 64 bit words
* the number of bits specified in creation can be any number > 0
Implementation notes:
* MY_BITMAP includes a pointer, last_word_ptr, to the last word.
The implication is that if one copies bitmaps to another memory
location, one has to call create_last_bit_mask() on the bitmap to
fix the internal pointer.
* The not used part of a the last word should always be 0.
This avoids special handling of the last bitmap in several cases.
This is checked for most calls to bitmap functions.
TODO:
Make assembler thread safe versions of these using test-and-set instructions
@ -31,95 +42,94 @@
New version written and test program added and some changes to the interface
was made by Mikael Ronstrom 2005, with assistance of Tomas Ulin and Mats
Kindahl.
Updated to 64 bits and use my_find_first_bit() to speed up
bitmap_get_next_set() by Monty in 2024
*/
#include "mysys_priv.h"
#include <my_bitmap.h>
#include <m_string.h>
#include <my_bit.h>
#include <my_byteorder.h>
/* Defines to check bitmaps */
#define DBUG_ASSERT_BITMAP(M) \
DBUG_ASSERT((M)->bitmap); \
DBUG_ASSERT((M)->n_bits > 0); \
DBUG_ASSERT((M)->last_word_ptr == (M)->bitmap + no_words_in_map(M)-1); \
DBUG_ASSERT((*(M)->last_word_ptr & (M)->last_bit_mask) == 0);
#define DBUG_ASSERT_BITMAP_AND_BIT(M,B) \
DBUG_ASSERT_BITMAP(M); \
DBUG_ASSERT((B) < (M)->n_bits);
#define DBUG_ASSERT_DIFFERENT_BITMAPS(M,N) \
DBUG_ASSERT_BITMAP(M); \
DBUG_ASSERT_BITMAP(N);
#define DBUG_ASSERT_IDENTICAL_BITMAPS(M,N) \
DBUG_ASSERT_BITMAP(M); \
DBUG_ASSERT_BITMAP(N); \
DBUG_ASSERT((M)->n_bits == (N)->n_bits);
/*
Create a mask with the upper 'unused' bits set and the lower 'used'
bits clear. The bits within each byte is stored in big-endian order.
Create a mask for the usable bits on the LAST my_bitmap_map position for
a bitmap with 'bits' number of bits.
The lowest 'bits' bits are set to zero and the rest bits are set to 1.
For (bits & 63) == 0 , 0 is returned as in this case all bits in the
my_bitmap_position are significant. (This example assumes the
storage is ulonglong).
For 'bits & 63' it will return values from the series
0, 0xfffffffffffffffe,.... 0x8000000000000000
*/
static inline uchar invers_last_byte_mask(uint bits)
static inline my_bitmap_map last_bit_mask(uint bits)
{
return last_byte_mask(bits) ^ 255;
uint bits_in_last_map= (bits & (my_bitmap_map_bits-1));
return bits_in_last_map ? ~((1ULL << bits_in_last_map)-1) : 0ULL;
}
void create_last_word_mask(MY_BITMAP *map)
/*
Get a mask of the bits that are to be considered as 'on' at location
starting with 'bits'.
This function has _inv in it's name as it's usage is invers compared
to last_bit_mask().
For (bits & 63) it will return values from the series
0xffffffffffffffff, 0xfffffffffffffffe,.... 0x8000000000000000
*/
static inline my_bitmap_map first_bit_mask_inv(uint bits)
{
unsigned char const mask= invers_last_byte_mask(map->n_bits);
/*
The first bytes are to be set to zero since they represent real bits
in the bitvector. The last bytes are set to 0xFF since they represent
bytes not used by the bitvector. Finally the last byte contains bits
as set by the mask above.
*/
unsigned char *ptr= (unsigned char*)&map->last_word_mask;
map->last_word_ptr= map->bitmap + no_words_in_map(map)-1;
switch (no_bytes_in_map(map) & 3) {
case 1:
map->last_word_mask= ~0U;
ptr[0]= mask;
return;
case 2:
map->last_word_mask= ~0U;
ptr[0]= 0;
ptr[1]= mask;
return;
case 3:
map->last_word_mask= 0U;
ptr[2]= mask;
ptr[3]= 0xFFU;
return;
case 0:
map->last_word_mask= 0U;
ptr[3]= mask;
return;
}
uint bits_in_last_map= (bits & (my_bitmap_map_bits-1));
return ~((1ULL << bits_in_last_map)-1);
}
static inline my_bitmap_map last_word_mask(uint bit)
/*
Update the bitmap's last_word_ptr and last_bit_mask
Also ensure that the last world is all zero to make it
easy to find the next set bit.
Note that if n_bits is 0, then last_word_ptr will point to
bitmap (safely). The bitmap will not be usable for almost any operation.
*/
void create_last_bit_mask(MY_BITMAP *map)
{
my_bitmap_map last_word_mask;
uint n_bits= bit + 1;
unsigned char const mask= invers_last_byte_mask(n_bits);
/*
The first bytes are to be set to zero since they represent real bits
in the bitvector. The last bytes are set to 0xFF since they represent
bytes not used by the bitvector. Finally the last byte contains bits
as set by the mask above.
*/
unsigned char *ptr= (unsigned char*)&last_word_mask;
switch ((n_bits + 7)/8 & 3) {
case 1:
last_word_mask= ~0U;
ptr[0]= mask;
break;
case 2:
last_word_mask= ~0U;
ptr[0]= 0;
ptr[1]= mask;
break;
case 3:
last_word_mask= 0U;
ptr[2]= mask;
ptr[3]= 0xFFU;
break;
case 0:
last_word_mask= 0U;
ptr[3]= mask;
break;
my_bitmap_map mask= last_bit_mask(map->n_bits);
map->last_bit_mask= mask;
map->last_word_ptr= map->bitmap + MY_MAX(no_words_in_map(map),1) -1;
if (map->n_bits > 0)
{
*map->last_word_ptr&= ~mask; /* Set not used bits to 0 */
DBUG_ASSERT_BITMAP(map);
}
return last_word_mask;
}
@ -136,25 +146,6 @@ static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
}
static inline uint get_first_set(my_bitmap_map value, uint word_pos)
{
uchar *byte_ptr= (uchar*)&value;
uchar byte_value;
uint byte_pos, bit_pos;
DBUG_ASSERT(value);
for (byte_pos=0; ; byte_pos++, byte_ptr++)
{
if ((byte_value= *byte_ptr))
{
for (bit_pos=0; ; bit_pos++)
if (byte_value & (1 << bit_pos))
return (word_pos*32) + (byte_pos*8) + bit_pos;
}
}
return MY_BIT_NONE; /* Impossible */
}
/*
Initialize a bitmap object. All bits will be set to zero
*/
@ -164,6 +155,7 @@ my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
{
DBUG_ENTER("my_bitmap_init");
map->mutex= 0;
if (!buf)
{
uint size_in_bytes= bitmap_buffer_size(n_bits);
@ -175,21 +167,26 @@ my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
}
if (!(buf= (my_bitmap_map*) my_malloc(key_memory_MY_BITMAP_bitmap,
size_in_bytes+extra, MYF(MY_WME))))
{
map->bitmap= 0;
DBUG_RETURN(1);
}
if (thread_safe)
{
map->mutex= (mysql_mutex_t *) ((char*) buf + size_in_bytes);
mysql_mutex_init(key_BITMAP_mutex, map->mutex, MY_MUTEX_INIT_FAST);
}
map->bitmap_allocated= 1;
}
else
{
DBUG_ASSERT(thread_safe == 0);
map->bitmap_allocated= 0;
}
map->bitmap= buf;
map->n_bits= n_bits;
create_last_word_mask(map);
create_last_bit_mask(map);
bitmap_clear_all(map);
DBUG_RETURN(0);
}
@ -202,7 +199,8 @@ void my_bitmap_free(MY_BITMAP *map)
{
if (map->mutex)
mysql_mutex_destroy(map->mutex);
my_free(map->bitmap);
if (map->bitmap_allocated)
my_free(map->bitmap);
map->bitmap=0;
}
DBUG_VOID_RETURN;
@ -227,6 +225,7 @@ my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
uchar *value= ((uchar*) map->bitmap) + (bitmap_bit / 8);
uchar bit= 1 << ((bitmap_bit) & 7);
uchar res= (*value) & bit;
DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
*value|= bit;
return res;
}
@ -248,8 +247,7 @@ my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
{
my_bool res;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(bitmap_bit < map->n_bits);
DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
bitmap_lock(map);
res= bitmap_fast_test_and_set(map, bitmap_bit);
bitmap_unlock(map);
@ -274,6 +272,8 @@ my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
uchar bit= 1 << ((bitmap_bit) & 7);
uchar res= (*byte) & bit;
DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
*byte&= ~bit;
return res;
}
@ -282,8 +282,8 @@ my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
{
my_bool res;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(bitmap_bit < map->n_bits);
DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
bitmap_lock(map);
res= bitmap_fast_test_and_clear(map, bitmap_bit);
bitmap_unlock(map);
@ -294,8 +294,8 @@ my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
uint bitmap_set_next(MY_BITMAP *map)
{
uint bit_found;
DBUG_ASSERT(map->bitmap);
if ((bit_found= bitmap_get_first(map)) != MY_BIT_NONE)
DBUG_ASSERT_BITMAP(map);
if ((bit_found= bitmap_get_first_clear(map)) != MY_BIT_NONE)
bitmap_set_bit(map, bit_found);
return bit_found;
}
@ -305,15 +305,16 @@ uint bitmap_set_next(MY_BITMAP *map)
Set the specified number of bits in the bitmap buffer.
@param map [IN] Bitmap
@param prefix_size [IN] Number of bits to be set
@param prefix_size [IN] Number of bits to be set or (uint) ~0 for all
*/
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
{
uint prefix_bytes, prefix_bits, d;
uchar *m= (uchar *)map->bitmap;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT_BITMAP(map);
DBUG_ASSERT(prefix_size <= map->n_bits || prefix_size == (uint) ~0);
set_if_smaller(prefix_size, map->n_bits);
if ((prefix_bytes= prefix_size / 8))
memset(m, 0xff, prefix_bytes);
@ -326,37 +327,45 @@ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
}
if ((d= no_bytes_in_map(map)-prefix_bytes))
memset(m, 0, d);
DBUG_ASSERT_BITMAP(map);
}
/**
Check if bitmap is a bitmap of prefix bits set in the beginning
@param map bitmap
@param prefix_size number of bits that should be set. 0 is allowed.
@return 1 Yes, prefix bits where set or prefix_size == 0.
@return 0 No
*/
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
{
uint prefix_mask= last_byte_mask(prefix_size);
uchar *m= (uchar*) map->bitmap;
uchar *end_prefix= m+(prefix_size-1)/8;
uchar *end;
DBUG_ASSERT(m);
DBUG_ASSERT(prefix_size <= map->n_bits);
/* Empty prefix is always true */
if (!prefix_size)
return 1;
DBUG_ASSERT_BITMAP_AND_BIT(map, prefix_size-1);
while (m < end_prefix)
if (*m++ != 0xff)
return 0;
end= ((uchar*) map->bitmap) + no_bytes_in_map(map) - 1;
if (m == end)
return ((*m & last_byte_mask(map->n_bits)) == prefix_mask);
end= ((uchar*) map->last_word_ptr) + sizeof(*map->last_word_ptr)-1;
if (*m != prefix_mask)
return 0;
while (++m < end)
while (++m <= end)
if (*m != 0)
return 0;
return ((*m & last_byte_mask(map->n_bits)) == 0);
return 1;
}
@ -364,10 +373,12 @@ my_bool bitmap_is_set_all(const MY_BITMAP *map)
{
my_bitmap_map *data_ptr= map->bitmap;
my_bitmap_map *end= map->last_word_ptr;
DBUG_ASSERT_BITMAP(map);
for (; data_ptr < end; data_ptr++)
if (*data_ptr != 0xFFFFFFFF)
if (*data_ptr != ~(my_bitmap_map)0)
return FALSE;
return (*data_ptr | map->last_word_mask) == 0xFFFFFFFF;
return (*data_ptr | map->last_bit_mask) == ~(my_bitmap_map)0;
}
@ -375,61 +386,58 @@ my_bool bitmap_is_clear_all(const MY_BITMAP *map)
{
my_bitmap_map *data_ptr= map->bitmap;
my_bitmap_map *end= map->last_word_ptr;
DBUG_ASSERT_BITMAP(map);
DBUG_ASSERT(map->n_bits > 0);
for (; data_ptr < end; data_ptr++)
for (; data_ptr <= end; data_ptr++)
if (*data_ptr)
return FALSE;
return (*data_ptr & ~map->last_word_mask) == 0;
return TRUE;
}
/* Return TRUE if map1 is a subset of map2 */
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end= map1->last_word_ptr;
DBUG_ASSERT_IDENTICAL_BITMAPS(map1,map2);
DBUG_ASSERT(map1->bitmap && map2->bitmap);
DBUG_ASSERT(map1->n_bits==map2->n_bits);
end= map1->last_word_ptr;
while (m1 < end)
while (m1 <= end)
{
if ((*m1++) & ~(*m2++))
return 0;
}
/* here both maps have the same number of bits - see assert above */
return ((*m1 & ~*m2 & ~map1->last_word_mask) ? 0 : 1);
return 1;
}
/* True if bitmaps has any common bits */
my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end= map1->last_word_ptr;
DBUG_ASSERT_IDENTICAL_BITMAPS(map1,map2);
DBUG_ASSERT(map1->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT(map1->n_bits==map2->n_bits);
end= map1->last_word_ptr;
while (m1 < end)
while (m1 <= end)
{
if ((*m1++) & (*m2++))
return 1;
}
/* here both maps have the same number of bits - see assert above */
return ((*m1 & *m2 & ~map1->last_word_mask) ? 1 : 0);
return 0;
}
/*
Create intersection of two bitmaps
@param map map1. Result is stored here
@param map2 map2
*/
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
{
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT_DIFFERENT_BITMAPS(map,map2);
end= to+MY_MIN(len,len2);
while (to < end)
@ -437,7 +445,7 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
if (len2 <= len)
{
to[-1]&= ~map2->last_word_mask; /* Clear last not relevant bits */
to[-1]&= ~map2->last_bit_mask; /* Clear last not relevant bits */
end+= len-len2;
while (to < end)
*to++= 0;
@ -447,50 +455,51 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
/*
Check if there is some bit index between start_bit and end_bit, such that
this is bit is set for all bitmaps in bitmap_list.
this is at least on bit that set for all bitmaps in bitmap_list.
SYNOPSIS
bitmap_exists_intersection()
bitmpap_array [in] a set of MY_BITMAPs
bitmap_count [in] number of elements in bitmpap_array
bitmap_count [in] number of elements in bitmap_array
start_bit [in] beginning (inclusive) of the range of bits to search
end_bit [in] end (inclusive) of the range of bits to search, must be
no bigger than the bits of the shortest bitmap.
NOTES
This function assumes that for at least one of the bitmaps in bitmap_array all
bits outside the range [start_bit, end_bit] are 0. As a result is not
necessary to take care of the bits outside the range [start_bit, end_bit].
RETURN
TRUE if an intersecion exists
FALSE no intersection
*/
my_bool bitmap_exists_intersection(const MY_BITMAP **bitmap_array,
my_bool bitmap_exists_intersection(MY_BITMAP **bitmap_array,
uint bitmap_count,
uint start_bit, uint end_bit)
{
uint i, j, start_idx, end_idx;
my_bitmap_map cur_res;
my_bitmap_map cur_res, first_map;
DBUG_ASSERT(bitmap_count);
DBUG_ASSERT(end_bit >= start_bit);
for (j= 0; j < bitmap_count; j++)
DBUG_ASSERT(end_bit < bitmap_array[j]->n_bits);
{
DBUG_ASSERT_BITMAP_AND_BIT(bitmap_array[j], end_bit);
}
start_idx= start_bit/8/sizeof(my_bitmap_map);
end_idx= end_bit/8/sizeof(my_bitmap_map);
first_map= first_bit_mask_inv(start_bit);
cur_res= first_map;
for (i= start_idx; i < end_idx; i++)
{
cur_res= ~0;
for (j= 0; cur_res && j < bitmap_count; j++)
cur_res &= bitmap_array[j]->bitmap[i];
if (cur_res)
return TRUE;
cur_res= ~(my_bitmap_map) 0;
}
cur_res= ~last_word_mask(end_bit);
cur_res= ~last_bit_mask(end_bit+1);
if (start_idx == end_idx)
cur_res&= first_map;
for (j= 0; cur_res && j < bitmap_count; j++)
cur_res &= bitmap_array[j]->bitmap[end_idx];
return cur_res != 0;
@ -501,60 +510,21 @@ my_bool bitmap_exists_intersection(const MY_BITMAP **bitmap_array,
my_bool bitmap_union_is_set_all(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end= map1->last_word_ptr;
DBUG_ASSERT_IDENTICAL_BITMAPS(map1,map2);
DBUG_ASSERT(map1->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT(map1->n_bits==map2->n_bits);
end= map1->last_word_ptr;
while ( m1 < end)
if ((*m1++ | *m2++) != 0xFFFFFFFF)
if ((*m1++ | *m2++) != ~(my_bitmap_map)0)
return FALSE;
/* here both maps have the same number of bits - see assert above */
return ((*m1 | *m2 | map1->last_word_mask) != 0xFFFFFFFF);
}
/*
Set/clear all bits above a bit.
SYNOPSIS
bitmap_set_above()
map RETURN The bitmap to change.
from_byte The bitmap buffer byte offset to start with.
use_bit The bit value (1/0) to use for all upper bits.
NOTE
You can only set/clear full bytes.
The function is meant for the situation that you copy a smaller bitmap
to a bigger bitmap. Bitmap lengths are always multiple of eigth (the
size of a byte). Using 'from_byte' saves multiplication and division
by eight during parameter passing.
RETURN
void
*/
void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
{
uchar use_byte= use_bit ? 0xff : 0;
uchar *to= (uchar *)map->bitmap + from_byte;
uchar *end= (uchar *)map->bitmap + (map->n_bits+7)/8;
while (to < end)
*to++= use_byte;
return ((*m1 | *m2 | map1->last_bit_mask) != ~(my_bitmap_map)0);
}
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
{
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT(map->n_bits==map2->n_bits);
end= map->last_word_ptr;
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT_IDENTICAL_BITMAPS(map,map2);
while (to <= end)
*to++ &= ~(*from++);
@ -563,12 +533,8 @@ void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
{
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT(map->n_bits == map2->n_bits);
end= map->last_word_ptr;
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT_IDENTICAL_BITMAPS(map,map2);
while (to <= end)
*to++ |= *from++;
@ -578,9 +544,8 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
{
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT(map->n_bits == map2->n_bits);
DBUG_ASSERT_IDENTICAL_BITMAPS(map,map2);
while (to <= end)
*to++ ^= *from++;
}
@ -588,13 +553,14 @@ void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
void bitmap_invert(MY_BITMAP *map)
{
my_bitmap_map *to= map->bitmap, *end;
my_bitmap_map *to= map->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT_BITMAP(map);
DBUG_ASSERT(map->bitmap);
end= map->last_word_ptr;
while (to < end)
*to++ ^= ~(my_bitmap_map)0;
while (to <= end)
*to++ ^= 0xFFFFFFFF;
*to ^= (~(my_bitmap_map)0 & ~map->last_bit_mask);
DBUG_ASSERT_BITMAP(map);
}
@ -603,45 +569,54 @@ uint bitmap_bits_set(const MY_BITMAP *map)
my_bitmap_map *data_ptr= map->bitmap;
my_bitmap_map *end= map->last_word_ptr;
uint res= 0;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT_BITMAP(map);
for (; data_ptr < end; data_ptr++)
res+= my_count_bits_uint32(*data_ptr);
for (; data_ptr <= end; data_ptr++)
res+= my_count_bits(*data_ptr);
/*Reset last bits to zero*/
res+= my_count_bits_uint32(*map->last_word_ptr & ~map->last_word_mask);
return res;
}
void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
/**
Copy bitmaps
@param map1 to-bitmap
@param map2 from-bitmap
@notes
Code will work even of the bitmaps are of different size.
In this case, only up to to->n_bits will be copied.
*/
void bitmap_copy(MY_BITMAP *map1, const MY_BITMAP *map2)
{
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
my_bitmap_map *to= map1->bitmap, *from= map2->bitmap;
uint map1_length= no_words_in_map(map1)*sizeof(my_bitmap_map);
uint map2_length= no_words_in_map(map2)*sizeof(my_bitmap_map);
uint length= MY_MIN(map1_length, map2_length);
DBUG_ASSERT_DIFFERENT_BITMAPS(map1,map2);
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
DBUG_ASSERT(map->n_bits == map2->n_bits);
end= map->last_word_ptr;
while (to <= end)
*to++ = *from++;
memcpy(to, from, length);
if (length < map1_length)
bzero(to + length, map1_length - length);
*map1->last_word_ptr&= ~map1->last_bit_mask;
}
/*
Find first set bit in the bitmap
*/
uint bitmap_get_first_set(const MY_BITMAP *map)
{
uint i;
my_bitmap_map *data_ptr= map->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT_BITMAP(map);
DBUG_ASSERT(map->bitmap);
for (i=0; data_ptr < end; data_ptr++, i++)
for (uint i=0; data_ptr <= end; data_ptr++, i++)
if (*data_ptr)
goto found;
if (!(*data_ptr & ~map->last_word_mask))
return MY_BIT_NONE;
found:
return get_first_set(*data_ptr, i);
return my_find_first_bit(*data_ptr) + i * sizeof(my_bitmap_map)*8;
return MY_BIT_NONE;
}
@ -656,82 +631,54 @@ found:
uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit)
{
uint word_pos, byte_to_mask, i;
union { my_bitmap_map bitmap ; uchar bitmap_buff[sizeof(my_bitmap_map)]; }
first_word;
uchar *ptr= &first_word.bitmap_buff[0];
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
DBUG_ASSERT(map->bitmap);
uint word_pos;
my_bitmap_map first_word, *data_ptr, *end= map->last_word_ptr;
DBUG_ASSERT_BITMAP(map);
/* Look for the next bit */
bitmap_bit++;
if (bitmap_bit >= map->n_bits)
return MY_BIT_NONE;
word_pos= bitmap_bit / 32;
word_pos= bitmap_bit / 64;
data_ptr= map->bitmap + word_pos;
first_word.bitmap= *data_ptr;
/* Mask out previous bits from first_word */
byte_to_mask= (bitmap_bit % 32) / 8;
for (i= 0; i < byte_to_mask; i++)
ptr[i]= 0;
ptr[byte_to_mask]&= 0xFFU << (bitmap_bit & 7);
first_word= *data_ptr & first_bit_mask_inv(bitmap_bit);
if (data_ptr == end)
if (first_word)
{
if (first_word.bitmap & ~map->last_word_mask)
return get_first_set(first_word.bitmap, word_pos);
else
return MY_BIT_NONE;
/* Optimize common case when most bits are set */
if (first_word & (1ULL << ((bitmap_bit & (my_bitmap_map_bits-1)))))
return bitmap_bit;
return my_find_first_bit(first_word) + (bitmap_bit & ~(my_bitmap_map_bits-1));
}
if (first_word.bitmap)
return get_first_set(first_word.bitmap, word_pos);
for (data_ptr++, word_pos++; data_ptr < end; data_ptr++, word_pos++)
for (data_ptr++; data_ptr <= end; data_ptr++)
{
bitmap_bit+= 64;
if (*data_ptr)
return get_first_set(*data_ptr, word_pos);
if (!(*end & ~map->last_word_mask))
return MY_BIT_NONE;
return get_first_set(*end, word_pos);
return my_find_first_bit(*data_ptr) + (bitmap_bit & ~(my_bitmap_map_bits-1));
}
return MY_BIT_NONE;
}
/* Get first free bit */
/* Get first clear bit */
uint bitmap_get_first(const MY_BITMAP *map)
uint bitmap_get_first_clear(const MY_BITMAP *map)
{
uchar *byte_ptr;
uint i,j,k;
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
uint i;
my_bitmap_map *data_ptr= map->bitmap, *end= map->last_word_ptr;
DBUG_ASSERT_BITMAP(map);
DBUG_ASSERT(map->bitmap);
data_ptr= map->bitmap;
*map->last_word_ptr|= map->last_word_mask;
for (i=0; data_ptr < end; data_ptr++, i++)
if (*data_ptr != 0xFFFFFFFF)
for (i= 0; data_ptr < end; data_ptr++, i++)
if (*data_ptr != ~(my_bitmap_map)0)
goto found;
if ((*data_ptr | map->last_word_mask) == 0xFFFFFFFF)
if ((*data_ptr | map->last_bit_mask) == ~(my_bitmap_map)0)
return MY_BIT_NONE;
found:
byte_ptr= (uchar*)data_ptr;
for (j=0; ; j++, byte_ptr++)
{
if (*byte_ptr != 0xFF)
{
for (k=0; ; k++)
{
if (!(*byte_ptr & (1 << k)))
return (i*32) + (j*8) + k;
}
}
}
DBUG_ASSERT(0);
return MY_BIT_NONE; /* Impossible */
/* find first zero bit by reverting all bits and find first bit */
return my_find_first_bit(~*data_ptr) + i * sizeof(my_bitmap_map)*8;
}
@ -753,4 +700,3 @@ void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit)
bitmap_clear_bit(map, bitmap_bit);
bitmap_unlock(map);
}

View File

@ -3731,7 +3731,7 @@ bool ha_partition::init_partition_bitmaps()
if (my_bitmap_init(&m_key_not_found_partitions, NULL, m_tot_parts, FALSE))
DBUG_RETURN(true);
if (bitmap_init(&m_mrr_used_partitions, NULL, m_tot_parts, TRUE))
if (my_bitmap_init(&m_mrr_used_partitions, NULL, m_tot_parts, TRUE))
DBUG_RETURN(true);
if (my_bitmap_init(&m_opened_partitions, NULL, m_tot_parts, FALSE))

View File

@ -6706,9 +6706,10 @@ exists_complementing_null_row(MY_BITMAP *keys_to_complement)
return FALSE;
}
return bitmap_exists_intersection((const MY_BITMAP**) null_bitmaps,
return bitmap_exists_intersection(null_bitmaps,
count_null_keys,
(uint)highest_min_row, (uint)lowest_max_row);
(uint)highest_min_row,
(uint)lowest_max_row);
}

View File

@ -3387,22 +3387,18 @@ Rows_log_event::Rows_log_event(const uchar *buf, uint event_len,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
{
DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
memcpy(m_cols.bitmap, ptr_after_width, (m_width + 7) / 8);
create_last_word_mask(&m_cols);
create_last_bit_mask(&m_cols); // Needed to fix last part of bitmap
ptr_after_width+= (m_width + 7) / 8;
DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
}
else
{
// Needed because my_bitmap_init() does not set it to null on failure
m_cols.bitmap= NULL;
DBUG_VOID_RETURN;
}
m_cols_ai.bitmap= m_cols.bitmap; /* See explanation in is_valid() */
@ -3412,23 +3408,20 @@ Rows_log_event::Rows_log_event(const uchar *buf, uint event_len,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols_ai,
m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
m_width,
false)))
m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai :
NULL,
m_width,
false)))
{
DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
memcpy(m_cols_ai.bitmap, ptr_after_width, (m_width + 7) / 8);
create_last_word_mask(&m_cols_ai);
create_last_bit_mask(&m_cols_ai); // Needed to fix last part of bitmap
ptr_after_width+= (m_width + 7) / 8;
DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
no_bytes_in_map(&m_cols_ai));
}
else
{
// Needed because my_bitmap_init() does not set it to null on failure
m_cols_ai.bitmap= 0;
DBUG_VOID_RETURN;
}
}
const uchar* const ptr_rows_data= (const uchar*) ptr_after_width;
@ -3491,8 +3484,6 @@ void Rows_log_event::uncompress_buf()
Rows_log_event::~Rows_log_event()
{
if (m_cols.bitmap == m_bitbuf) // no my_malloc happened
m_cols.bitmap= 0; // so no my_free in my_bitmap_free
my_bitmap_free(&m_cols); // To pair with my_bitmap_init().
my_free(m_rows_buf);
my_free(m_extra_row_data);
@ -4058,12 +4049,7 @@ Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
Update_rows_log_event::~Update_rows_log_event()
{
if (m_cols_ai.bitmap)
{
if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
m_cols_ai.bitmap= 0; // so no my_free in my_bitmap_free
my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init().
}
my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init().
}

View File

@ -5163,8 +5163,8 @@ protected:
ulong m_master_reclength; /* Length of record on master side */
/* Bit buffers in the same memory as the class */
uint32 m_bitbuf[128/(sizeof(uint32)*8)];
uint32 m_bitbuf_ai[128/(sizeof(uint32)*8)];
my_bitmap_map m_bitbuf[128/(sizeof(my_bitmap_map)*8)];
my_bitmap_map m_bitbuf_ai[128/(sizeof(my_bitmap_map)*8)];
uchar *m_rows_buf; /* The rows in packed format */
uchar *m_rows_cur; /* One-after the end of the data */

View File

@ -1156,21 +1156,13 @@ Old_rows_log_event::Old_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
set_flags(RELAXED_UNIQUE_CHECKS_F);
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
{
/* Cols can be zero if this is a dummy binrows event */
if (likely(cols != NULL))
{
memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
create_last_word_mask(&m_cols);
}
}
else
{
// Needed because my_bitmap_init() does not set it to null on failure
m_cols.bitmap= 0;
bitmap_copy(&m_cols, cols);
}
}
#endif
@ -1232,13 +1224,13 @@ Old_rows_log_event::Old_rows_log_event(const uchar *buf, uint event_len,
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
{
DBUG_PRINT("debug", ("Reading from %p", ptr_after_width));
memcpy(m_cols.bitmap, ptr_after_width, (m_width + 7) / 8);
create_last_word_mask(&m_cols);
create_last_bit_mask(&m_cols); // Needed to fix last part of bitmap
ptr_after_width+= (m_width + 7) / 8;
DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
}
@ -1274,8 +1266,6 @@ Old_rows_log_event::Old_rows_log_event(const uchar *buf, uint event_len,
Old_rows_log_event::~Old_rows_log_event()
{
if (m_cols.bitmap == m_bitbuf) // no my_malloc happened
m_cols.bitmap= 0; // so no my_free in my_bitmap_free
my_bitmap_free(&m_cols); // To pair with my_bitmap_init().
my_free(m_rows_buf);
}

View File

@ -183,8 +183,8 @@ protected:
ulong m_master_reclength; /* Length of record on master side */
/* Bit buffers in the same memory as the class */
uint32 m_bitbuf[128/(sizeof(uint32)*8)];
uint32 m_bitbuf_ai[128/(sizeof(uint32)*8)];
my_bitmap_map m_bitbuf[128/(sizeof(my_bitmap_map)*8)];
my_bitmap_map m_bitbuf_ai[128/(sizeof(my_bitmap_map)*8)];
uchar *m_rows_buf; /* The rows in packed format */
uchar *m_rows_cur; /* One-after the end of the data */

View File

@ -5289,21 +5289,13 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg,
set_flags(NO_CHECK_CONSTRAINT_CHECKS_F);
/* if my_bitmap_init fails, caught in is_valid() */
if (likely(!my_bitmap_init(&m_cols,
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
m_width,
false)))
{
/* Cols can be zero if this is a dummy binrows event */
if (likely(cols != NULL))
{
memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
create_last_word_mask(&m_cols);
}
}
else
{
// Needed because my_bitmap_init() does not set it to null on failure
m_cols.bitmap= 0;
bitmap_copy(&m_cols, cols);
}
}
@ -8401,7 +8393,7 @@ void Update_rows_log_event::init(MY_BITMAP const *cols)
if (likely(cols != NULL))
{
memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
create_last_word_mask(&m_cols_ai);
create_last_bit_mask(&m_cols_ai); // Needed to fix last part of bitmap
}
}
}

View File

@ -3582,7 +3582,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)
table->reginfo.impossible_range= 0;
uint used_fields_buff_size= bitmap_buffer_size(table->s->fields);
uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size);
my_bitmap_map *used_fields_buff= (my_bitmap_map*)thd->alloc(used_fields_buff_size);
MY_BITMAP cols_for_indexes;
(void) my_bitmap_init(&cols_for_indexes, used_fields_buff, table->s->fields, 0);
bitmap_clear_all(&cols_for_indexes);
@ -7439,7 +7439,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param,
(*scan)->used_fields_covered=
bitmap_bits_set(&(*scan)->covered_fields);
(*scan)->first_uncovered_field=
bitmap_get_first(&(*scan)->covered_fields);
bitmap_get_first_clear(&(*scan)->covered_fields);
}
my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*),

View File

@ -1419,7 +1419,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
*trans_end= trans_start + num;
Field_translator *trans;
uint used_fields_buff_size= bitmap_buffer_size(table->s->fields);
uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size);
my_bitmap_map *used_fields_buff= (my_bitmap_map*)thd->alloc(used_fields_buff_size);
MY_BITMAP used_fields;
enum_column_usage saved_column_usage= thd->column_usage;
DBUG_ENTER("check_key_in_view");
@ -2828,6 +2828,8 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
copy->def_read_set.bitmap= (my_bitmap_map*) bitmap;
copy->def_write_set.bitmap= ((my_bitmap_map*)
(bitmap + share->column_bitmap_size));
create_last_bit_mask(&copy->def_read_set);
create_last_bit_mask(&copy->def_write_set);
bitmaps_used= 2;
if (share->default_fields || share->default_expressions)
{

View File

@ -1085,7 +1085,7 @@ void check_range_capable_PF(TABLE *table)
static bool set_up_partition_bitmaps(THD *thd, partition_info *part_info)
{
uint32 *bitmap_buf;
my_bitmap_map *bitmap_buf;
uint bitmap_bits= part_info->num_subparts?
(part_info->num_subparts* part_info->num_parts):
part_info->num_parts;
@ -1096,14 +1096,15 @@ static bool set_up_partition_bitmaps(THD *thd, partition_info *part_info)
/* Allocate for both read and lock_partitions */
if (unlikely(!(bitmap_buf=
(uint32*) alloc_root(&part_info->table->mem_root,
bitmap_bytes * 2))))
(my_bitmap_map*) alloc_root(&part_info->table->mem_root,
bitmap_bytes * 2))))
DBUG_RETURN(TRUE);
my_bitmap_init(&part_info->read_partitions, bitmap_buf, bitmap_bits, FALSE);
/* Use the second half of the allocated buffer for lock_partitions */
my_bitmap_init(&part_info->lock_partitions, bitmap_buf + (bitmap_bytes / 4),
bitmap_bits, FALSE);
my_bitmap_init(&part_info->lock_partitions,
(my_bitmap_map*) (((char*) bitmap_buf) + bitmap_bytes),
bitmap_bits, FALSE);
part_info->bitmaps_are_initialized= TRUE;
part_info->set_partition_bitmaps(NULL);
DBUG_RETURN(FALSE);

View File

@ -4923,7 +4923,8 @@ int ha_mroonga::open(const char *name,
DBUG_RETURN(error);
thr_lock_data_init(&share->lock,&thr_lock_data,NULL);
if (bitmap_init(&multiple_column_key_bitmap, NULL, table->s->fields, false))
if (my_bitmap_init(&multiple_column_key_bitmap, NULL, table->s->fields,
false))
{
mrn_free_share(share);
share = NULL;
@ -4939,7 +4940,7 @@ int ha_mroonga::open(const char *name,
if (error)
{
bitmap_free(&multiple_column_key_bitmap);
my_bitmap_free(&multiple_column_key_bitmap);
mrn_free_share(share);
share = NULL;
}
@ -5017,7 +5018,7 @@ int ha_mroonga::close()
{
error = add_wrap_hton(share->table_name, share->hton);
}
bitmap_free(&multiple_column_key_bitmap);
my_bitmap_free(&multiple_column_key_bitmap);
if (share->use_count == 1) {
mrn_free_long_term_share(share->long_term_share);
}

View File

@ -26,7 +26,7 @@ namespace mrn {
SmartBitmap::~SmartBitmap() {
if (bitmap_) {
bitmap_free(bitmap_);
my_bitmap_free(bitmap_);
}
}

View File

@ -10832,7 +10832,7 @@ int ha_rocksdb::index_end() {
release_scan_iterator();
bitmap_free(&m_lookup_bitmap);
my_bitmap_free(&m_lookup_bitmap);
active_index = MAX_KEY;
in_range_check_pushed_down = FALSE;

View File

@ -397,7 +397,7 @@ class ha_rocksdb : public my_core::handler {
current lookup to be covered. If the bitmap field is null, that means this
index does not cover the current lookup for any record.
*/
MY_BITMAP m_lookup_bitmap = {nullptr, nullptr, nullptr, 0, 0};
MY_BITMAP m_lookup_bitmap = {nullptr, nullptr, nullptr, 0, 0, 0};
int alloc_key_buffers(const TABLE *const table_arg,
const Rdb_tbl_def *const tbl_def_arg,

View File

@ -1102,12 +1102,12 @@ size_t Rdb_key_def::get_unpack_header_size(char tag) {
*/
void Rdb_key_def::get_lookup_bitmap(const TABLE *table, MY_BITMAP *map) const {
DBUG_ASSERT(map->bitmap == nullptr);
bitmap_init(map, nullptr, MAX_REF_PARTS, false);
my_bitmap_init(map, nullptr, MAX_REF_PARTS, false);
uint curr_bitmap_pos = 0;
// Indicates which columns in the read set might be covered.
MY_BITMAP maybe_covered_bitmap;
bitmap_init(&maybe_covered_bitmap, nullptr, table->read_set->n_bits, false);
my_bitmap_init(&maybe_covered_bitmap, nullptr, table->read_set->n_bits, false);
for (uint i = 0; i < m_key_parts; i++) {
if (table_has_hidden_pk(table) && i + 1 == m_key_parts) {
@ -1135,8 +1135,8 @@ void Rdb_key_def::get_lookup_bitmap(const TABLE *table, MY_BITMAP *map) const {
}
curr_bitmap_pos++;
} else {
bitmap_free(&maybe_covered_bitmap);
bitmap_free(map);
my_bitmap_free(&maybe_covered_bitmap);
my_bitmap_free(map);
return;
}
break;
@ -1144,8 +1144,8 @@ void Rdb_key_def::get_lookup_bitmap(const TABLE *table, MY_BITMAP *map) const {
// know this lookup will never be covered.
default:
if (bitmap_is_set(table->read_set, field->field_index)) {
bitmap_free(&maybe_covered_bitmap);
bitmap_free(map);
my_bitmap_free(&maybe_covered_bitmap);
my_bitmap_free(map);
return;
}
break;
@ -1155,9 +1155,9 @@ void Rdb_key_def::get_lookup_bitmap(const TABLE *table, MY_BITMAP *map) const {
// If there are columns which are not covered in the read set, the lookup
// can't be covered.
if (!bitmap_cmp(table->read_set, &maybe_covered_bitmap)) {
bitmap_free(map);
my_bitmap_free(map);
}
bitmap_free(&maybe_covered_bitmap);
my_bitmap_free(&maybe_covered_bitmap);
}
/*
@ -1187,7 +1187,7 @@ bool Rdb_key_def::covers_lookup(const rocksdb::Slice *const unpack_info,
MY_BITMAP covered_bitmap;
my_bitmap_map covered_bits;
bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
my_bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
covered_bits = rdb_netbuf_to_uint16((const uchar *)unpack_header +
sizeof(RDB_UNPACK_COVERED_DATA_TAG) +
RDB_UNPACK_COVERED_DATA_LEN_SIZE);
@ -1356,7 +1356,7 @@ uint Rdb_key_def::pack_record(const TABLE *const tbl, uchar *const pack_buffer,
MY_BITMAP covered_bitmap;
my_bitmap_map covered_bits;
uint curr_bitmap_pos = 0;
bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
my_bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
for (uint i = 0; i < n_key_parts; i++) {
// Fill hidden pk id into the last key part for secondary keys for tables
@ -1661,7 +1661,7 @@ int Rdb_key_def::unpack_record(TABLE *const table, uchar *const buf,
bool has_covered_bitmap =
has_unpack_info && (unpack_header[0] == RDB_UNPACK_COVERED_DATA_TAG);
if (has_covered_bitmap) {
bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
my_bitmap_init(&covered_bitmap, &covered_bits, MAX_REF_PARTS, false);
covered_bits = rdb_netbuf_to_uint16((const uchar *)unpack_header +
sizeof(RDB_UNPACK_COVERED_DATA_TAG) +
RDB_UNPACK_COVERED_DATA_LEN_SIZE);

View File

@ -29,6 +29,8 @@
uint get_rand_bit(uint bitsize)
{
if (bitsize == 0)
return 0;
return (rand() % bitsize);
}
@ -266,7 +268,7 @@ my_bool test_get_first_bit(MY_BITMAP *map, uint bitsize)
bitmap_clear_all(map);
for (i=0; i < bitsize; i++)
bitmap_set_bit(map, i);
if (bitmap_get_first(map) != MY_BIT_NONE)
if (bitmap_get_first_clear(map) != MY_BIT_NONE)
goto error2;
bitmap_clear_all(map);
@ -278,7 +280,7 @@ my_bool test_get_first_bit(MY_BITMAP *map, uint bitsize)
goto error1;
bitmap_set_all(map);
bitmap_clear_bit(map, test_bit);
if (bitmap_get_first(map) != test_bit)
if (bitmap_get_first_clear(map) != test_bit)
goto error2;
bitmap_clear_all(map);
}
@ -297,14 +299,45 @@ my_bool test_get_next_bit(MY_BITMAP *map, uint bitsize)
uint no_loops= bitsize > 128 ? 128 : bitsize;
for (i=0; i < no_loops; i++)
{
uint count= 0, bits_set= 0;
bitmap_clear_all(map);
test_bit=get_rand_bit(bitsize);
for (j=0; j < test_bit; j++)
bitmap_set_next(map);
if (!bitmap_is_prefix(map, test_bit))
goto error1;
j= bitmap_get_first_set(map);
if (j == MY_BIT_NONE)
{
if (test_bit != 0)
goto error1;
continue;
}
count= 1;
while ((j= bitmap_get_next_set(map,j)) != MY_BIT_NONE)
count++;
if (count != test_bit)
goto error1;
if (test_bit < 3)
continue;
bitmap_clear_all(map);
for (j=1; j < test_bit; j+=2)
{
bits_set++;
bitmap_set_bit(map, j);
}
if ((j= bitmap_get_first_set(map)) == MY_BIT_NONE)
goto error1;
count= 1;
while ((j= bitmap_get_next_set(map,j)) != MY_BIT_NONE)
count++;
if (count != bits_set)
goto error1;
}
return FALSE;
error1:
diag("get_next error bitsize= %u, prefix_size= %u", bitsize,test_bit);
return TRUE;
@ -371,7 +404,7 @@ error5:
my_bool test_compare(MY_BITMAP *map, uint bitsize)
{
MY_BITMAP map2;
uint32 map2buf[MAX_TESTED_BITMAP_SIZE];
my_bitmap_map map2buf[MAX_TESTED_BITMAP_SIZE];
uint i, test_bit;
uint no_loops= bitsize > 128 ? 128 : bitsize;
if (my_bitmap_init(&map2, map2buf, bitsize, FALSE))
@ -431,7 +464,7 @@ my_bool test_intersect(MY_BITMAP *map, uint bitsize)
{
uint bitsize2 = 1 + get_rand_bit(MAX_TESTED_BITMAP_SIZE - 1);
MY_BITMAP map2;
uint32 map2buf[MAX_TESTED_BITMAP_SIZE];
my_bitmap_map map2buf[MAX_TESTED_BITMAP_SIZE];
uint i, test_bit1, test_bit2, test_bit3;
if (my_bitmap_init(&map2, map2buf, bitsize2, FALSE))
{
@ -477,6 +510,94 @@ error:
return TRUE;
}
my_bool test_copy(MY_BITMAP *map, uint bitsize)
{
my_bitmap_map buff[16];
MY_BITMAP map2;
my_bitmap_init(&map2, buff, sizeof(buff)*8, FALSE);
memset((void*) buff, 0xff, sizeof(buff));
bitsize= MY_MIN(bitsize, map2.n_bits);
bitmap_copy(map, &map2);
if (bitmap_bits_set(map) != bitsize)
{
diag("bitmap_copy failed on bitsize %d", bitsize);
return 1;
}
return 0;
}
static my_bool exec_bitmap_exists_intersection(MY_BITMAP **maps, uint bitsize,
uint start, uint end, uint bit)
{
bitmap_clear_all(maps[0]);
bitmap_clear_all(maps[1]);
bitmap_set_bit(maps[0], bit);
bitmap_set_bit(maps[1], bit);
return bitmap_exists_intersection(maps, 2, start, end);
}
my_bool test_bitmap_exists_intersection(MY_BITMAP *map, uint bitsize)
{
MY_BITMAP map2;
uint start_bit, end_bit, rnd_bit;
MY_BITMAP *maps[2];
maps[0]= map;
maps[1]= &map2;
my_bitmap_init(&map2, 0, bitsize, FALSE);
bitmap_clear_all(map);
bitmap_clear_all(&map2);
start_bit= get_rand_bit(bitsize);
end_bit= get_rand_bit(bitsize);
if (start_bit > end_bit)
swap_variables(uint, start_bit, end_bit);
rnd_bit= start_bit+get_rand_bit(end_bit-start_bit);
if (!exec_bitmap_exists_intersection(maps, bitsize, start_bit, end_bit,
rnd_bit))
goto err;
start_bit= end_bit= rnd_bit= 0;
if (!exec_bitmap_exists_intersection(maps, bitsize, start_bit, end_bit,
rnd_bit))
goto err;
start_bit= rnd_bit= 0 ; end_bit= bitsize-1;
if (!exec_bitmap_exists_intersection(maps, bitsize, start_bit, end_bit,
rnd_bit))
goto err;
start_bit= rnd_bit= end_bit= bitsize-1;
if (!exec_bitmap_exists_intersection(maps, bitsize, start_bit, end_bit,
rnd_bit))
goto err;
if (bitsize > 1)
{
start_bit= end_bit= 1 ; rnd_bit= 0;
if (exec_bitmap_exists_intersection(maps, bitsize, start_bit, end_bit,
rnd_bit))
goto err;
start_bit= end_bit= bitsize-1 ; rnd_bit= bitsize-2;
if (exec_bitmap_exists_intersection(maps, bitsize, start_bit, end_bit,
rnd_bit))
goto err;
}
my_bitmap_free(&map2);
return 0;
err:
diag("bitmap_exist_intersection failed on bitsize: %d start_bit: %d "
"end_bit: %d rnd_bit: %d",
bitsize, start_bit, end_bit, rnd_bit);
my_bitmap_free(&map2);
return 1;
}
my_bool do_test(uint bitsize)
{
MY_BITMAP map;
@ -515,6 +636,11 @@ my_bool do_test(uint bitsize)
bitmap_clear_all(&map);
if (test_intersect(&map,bitsize))
goto error;
bitmap_clear_all(&map);
if (test_copy(&map,bitsize))
goto error;
if (test_bitmap_exists_intersection(&map, bitsize))
goto error;
return FALSE;
error:
return TRUE;