← Back to team overview

maria-developers team mailing list archive

Re: [Commits] 2603dc0: MDEV-11084 Select statement with partition selection against MyISAM table opens all partitions.

 

Hi, Alexey!

That looked reasonable enough. I didn't find anything big.
Small comments - see below.

On Jun 01, Alexey Botchkov wrote:
> revision-id: 2603dc0d56ec90f308678a3c002f1b75af69f554 (mariadb-10.1.23-51-g2603dc0)
> parent(s): e4d10e09cf318aad237143254c45458d16009f70
> committer: Alexey Botchkov
> timestamp: 2017-06-01 17:33:34 +0400
> message:
> 
> MDEV-11084 Select statement with partition selection against MyISAM table opens all partitions.
> 
>         Now SELECT FROM t PARTITION(x) only opens the 'x' file.
>         The table->partition_names parameter is sent to ha_open
>         so it only opens the required partitions.
>         If the table is reopened, the
>         change_partition_to_open(partition_names) is called that
>         closes and opens partitions specified for the query.
> 
> diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
> index 29054c7..53a128c 100644
> --- a/sql/ha_partition.cc
> +++ b/sql/ha_partition.cc
> @@ -3481,12 +3498,16 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
>        }
>        name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
>      }
> +    file_sample= m_file[0];

are you sure that m_file[0] is opened?

>    }
>    else
>    {
>      file= m_file;
>      do
>      {
> +      if (!bitmap_is_set(&m_opened_partitions, file - m_file))
> +        continue;
> +
>        create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
>                              FALSE);
>        table->s->connect_string = m_connect_string[(uint)(file-m_file)];
> @@ -3494,20 +3515,21 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
>                                     test_if_locked | HA_OPEN_NO_PSI_CALL)))
>          goto err_handler;
>        bzero(&table->s->connect_string, sizeof(LEX_STRING));
> -      if (m_file == file)
> -        m_num_locks= (*file)->lock_count();
> +      if (!file_sample)
> +        m_num_locks= (file_sample= (*file))->lock_count();
>        DBUG_ASSERT(m_num_locks == (*file)->lock_count());
> -      name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
> -    } while (*(++file));
> +    } while (name_buffer_ptr+= strlen(name_buffer_ptr) + 1, *(++file));

why?

>    }
>    
>    file= m_file;
> -  ref_length= (*file)->ref_length;
> -  check_table_flags= (((*file)->ha_table_flags() &
> +  ref_length= file_sample->ref_length;
> +  check_table_flags= ((file_sample->ha_table_flags() &
>                         ~(PARTITION_DISABLED_TABLE_FLAGS)) |
>                        (PARTITION_ENABLED_TABLE_FLAGS));
>    while (*(++file))
>    {
> +    if (!bitmap_is_set(&m_opened_partitions, file - m_file))
> +      continue;
>      /* MyISAM can have smaller ref_length for partitions with MAX_ROWS set */
>      set_if_bigger(ref_length, ((*file)->ref_length));
>      /*
> @@ -6782,6 +6809,63 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
>  }
>  
>  
> +void ha_partition::set_partitions_to_open(List<String> *partition_names)
> +{
> +  m_partitions_to_open= partition_names;
> +}
> +
> +
> +int ha_partition::change_partitions_to_open(List<String> *partition_names)
> +{
> +  char name_buff[FN_REFLEN];
> +  handler **file;
> +  char *name_buffer_ptr;
> +  int error= 0;
> +
> +  if (m_is_clone_of)
> +    return 0;
> +
> +  m_partitions_to_open= partition_names;
> +  if ((error= m_part_info->set_partition_bitmaps(partition_names)))
> +    goto err_handler;
> +
> +  if (bitmap_cmp(&m_opened_partitions, &m_part_info->read_partitions) != 0)
> +    return 0;
> +
> +  if ((error= read_par_file(table->s->normalized_path.str)))
> +    goto err_handler;
> +
> +  name_buffer_ptr= m_name_buffer_ptr;
> +  file= m_file;
> +  do
> +  {
> +    int n_file= file-m_file;
> +    int is_open= bitmap_is_set(&m_opened_partitions, n_file);
> +    int should_be_open= bitmap_is_set(&m_part_info->read_partitions, n_file);
> +
> +    if (is_open && !should_be_open)
> +      (*file)->ha_close();
> +    else if (!is_open && should_be_open)
> +    {
> +      create_partition_name(name_buff, table->s->normalized_path.str,
> +                            name_buffer_ptr, NORMAL_PART_NAME, FALSE);
> +      table->s->connect_string = m_connect_string[(uint)(file-m_file)];
> +      if ((error= (*file)->ha_open(table, name_buff, m_mode,
> +                                   m_open_test_lock | HA_OPEN_NO_PSI_CALL)))
> +        goto err_handler;
> +      bzero(&table->s->connect_string, sizeof(LEX_STRING));
> +    }
> +  } while (name_buffer_ptr+= strlen(name_buffer_ptr) + 1, *(++file));

Could you reuse that, instead of copying from ::open?
Perhaps ::open() can reset the bitmap to be empty and then
call ::change_partitions_to_open() ?

Or the common code could be moved into a third function that these both
will use...

> +  
> +  bitmap_copy(&m_opened_partitions, &m_part_info->read_partitions);
> +
> +  clear_handler_file();
> +
> +err_handler:
> +  return error;
> +}
> +
> +
>  /**
>    General function to prepare handler for certain behavior.
>  
> diff --git a/sql/partition_info.cc b/sql/partition_info.cc
> index bc0db9e..7fb8f70 100644
> --- a/sql/partition_info.cc
> +++ b/sql/partition_info.cc
> @@ -283,6 +281,27 @@ bool partition_info::set_partition_bitmaps(TABLE_LIST *table_list)
>  
>  
>  /**
> +  Set read/lock_partitions bitmap over non pruned partitions
> +
> +  @param table_list   Possible TABLE_LIST which can contain
> +                      list of partition names to query
> +
> +  @return Operation status
> +    @retval FALSE  OK
> +    @retval TRUE   Failed to allocate memory for bitmap or list of partitions
> +                   did not match
> +
> +  @note OK to call multiple times without the need for free_bitmaps.
> +*/
> +bool partition_info::set_partition_bitmaps_from_table(TABLE_LIST *table_list)
> +{
> +  List<String> *partition_names= table_list ?
> +                                   NULL : table_list->partition_names;
> +  return set_partition_bitmaps(partition_names);
> +}

This looks unused.

> +
> +
> +/**
>    Checks if possible to do prune partitions on insert.
>  
>    @param thd           Thread context
> diff --git a/sql/sql_base.cc b/sql/sql_base.cc
> index 9c56b7d..2f9ec3e 100644
> --- a/sql/sql_base.cc
> +++ b/sql/sql_base.cc
> @@ -2533,6 +2533,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
>    {
>      DBUG_ASSERT(table->file != NULL);
>      MYSQL_REBIND_TABLE(table->file);
> +    if (table->part_info)
> +    {
> +      /* Set all [named] partitions as used. */
> +      if (table->file->change_partitions_to_open(table_list->partition_names))
> +        DBUG_RETURN(true);
> +    }
>    }
>    else
>    {
> @@ -2549,7 +2555,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
>                                           HA_TRY_READ_ONLY),
>                                   (READ_KEYINFO | COMPUTE_TYPES |
>                                    EXTRA_RECORD),
> -                                 thd->open_options, table, FALSE);
> +                                 thd->open_options, table, FALSE,
> +                                 table_list->partition_names);

Please, make sure you code compiles without partitioning too.
(in this case I wouldn't make the last argument of open_table_from_share
conditional, but I'd rather make table_list->partition_names unconditional).

>  
>      if (error)
>      {
> @@ -2598,9 +2605,11 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
>  #ifdef WITH_PARTITION_STORAGE_ENGINE
>    if (table->part_info)
>    {
> +#ifdef CODE_TO_REMOVE
>      /* Set all [named] partitions as used. */
>      if (table->part_info->set_partition_bitmaps(table_list))
>        DBUG_RETURN(true);
> +#endif /*CODE_TO_REMOVE*/

why not to remove at once?

>    }
>    else if (table_list->partition_names)
>    {

Regards,
Sergei
Chief Architect MariaDB
and security@xxxxxxxxxxx