diff --git a/include/my_bitmap.h b/include/my_bitmap.h index f19254404c1..5f722d9fbec 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -22,7 +22,7 @@ #include #include -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 } diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index bf2bacd213c..6a646a35fd1 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -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 #include #include +#include + + +/* 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); } - diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index f2b3ab3aff9..74805112823 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -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)) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index cc49d6a3d5d..99b31530d7d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -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); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 2acb77a2dc5..5719296746a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -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(). } diff --git a/sql/log_event.h b/sql/log_event.h index 8be46ed30cb..fca4015a15d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -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 */ diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index dff4ca29f6f..a7d5519276c 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -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); } diff --git a/sql/log_event_old.h b/sql/log_event_old.h index 1afe9aba60c..1281cb952ae 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -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 */ diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 96e5866e0cc..744a41ca782 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -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 } } } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2eaf0dc3c32..7bf712cff2b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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*), diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ec44e47a5d1..53992654706 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -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(©->def_read_set); + create_last_bit_mask(©->def_write_set); bitmaps_used= 2; if (share->default_fields || share->default_expressions) { diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 192e8c679d9..c8ffca03cff 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -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); diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 2b8b17d46e4..356a4a54280 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -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); } diff --git a/storage/mroonga/lib/mrn_smart_bitmap.cpp b/storage/mroonga/lib/mrn_smart_bitmap.cpp index f8fd4f727bb..cdedeb677cd 100644 --- a/storage/mroonga/lib/mrn_smart_bitmap.cpp +++ b/storage/mroonga/lib/mrn_smart_bitmap.cpp @@ -26,7 +26,7 @@ namespace mrn { SmartBitmap::~SmartBitmap() { if (bitmap_) { - bitmap_free(bitmap_); + my_bitmap_free(bitmap_); } } diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index 8030a1e3453..f8fb05f16e5 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -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; diff --git a/storage/rocksdb/ha_rocksdb.h b/storage/rocksdb/ha_rocksdb.h index 8580dcbc2e5..ee330dfa82a 100644 --- a/storage/rocksdb/ha_rocksdb.h +++ b/storage/rocksdb/ha_rocksdb.h @@ -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, diff --git a/storage/rocksdb/rdb_datadic.cc b/storage/rocksdb/rdb_datadic.cc index 939fb085c4f..4fc6265953b 100644 --- a/storage/rocksdb/rdb_datadic.cc +++ b/storage/rocksdb/rdb_datadic.cc @@ -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); diff --git a/unittest/mysys/bitmap-t.c b/unittest/mysys/bitmap-t.c index e8f41b32d2c..1f438dd67c5 100644 --- a/unittest/mysys/bitmap-t.c +++ b/unittest/mysys/bitmap-t.c @@ -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;