List:Commits« Previous MessageNext Message »
From:Sergei Golubchik Date:July 10 2007 10:02pm
Subject:Re: bk commit into 5.0 tree (thek:1.2489) BUG#28249
View as plain text  
Hi!

On Jul 09, kpettersson@stripped wrote:
> ChangeSet@stripped, 2007-07-09 10:09:31+02:00, thek@adventure.(none) +5 -0
>   Bug#28249 Query Cache returns wrong result with concurrent insert /
>   certain lock
>   
>   A race condition in the integration between MyISAM and the query
>   cache code caused the query cache to fail to invalidate itself on
>   concurrently inserted data.
>   
>   This patch fix this problem by using the existing handler interface
>   which, upon each statement cache attempt, compare the size of the
>   table as viewed from the cache writing thread and with any snap shot
>   of the global table state. If the two sizes are different the global
>   table size is unknown and the current statement can't be cached.
> 
> --- 1.178/sql/ha_myisam.cc	2007-03-28 10:22:20 +02:00
> +++ 1.179/sql/ha_myisam.cc	2007-07-09 10:09:29 +02:00
> @@ -1922,3 +1922,66 @@ uint ha_myisam::checksum() const
>    return (uint)file->state->checksum;
>  }
>  
> +#ifdef HAVE_QUERY_CACHE
> +/**
> +  @brief Register a named table with a call back function to the query cache.
> +
> +  @param thd The thread handle
> +  @param table_key A pointer to the table name in the table cache
> +  @param key_length The length of the table name
> +  @param[out] engine_callback The pointer to the storage engine call back
> +    function, currently 0
> +  @param[out] engine_data The table size as seen by the current thread.

No, don't return the table size in engine_data. It creates an impression
that this is actually needed for something, while, in fact, the value
will be ignored, so it's completely useless.

> +  @note Despite the name of this function, it is used to check each statement
> +    before it is cached and not to register a table or callback function.
> +
> +  @see handler::register_query_cache_table
> +
> +  @return Upon success the engine_callback will point to the storage engine
> +    call back function and engine_data will point to the data length of the
> +    specified table.
> +    @retval TRUE Success
> +    @retval FALSE An error occured
> +*/
> +
> +my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name,
> +                                              uint table_name_len,
> +                                              qc_engine_callback
> +                                              *engine_callback,
> +                                              ulonglong *engine_data)
> +{
> +  /*
> +    No call back function is needed to determine if a cached statement
> +    is valid or not.
> +  */
> +  *engine_callback= 0;
> +
> +  /*
> +    If a concurrent insert has happened just before the current select
> +    statement the total size of the table is unknown and the statement can't
> +    be cached. This works if the global table state is updated on the data lock
> +    before any query cache invalidation happens. An insert invalidation will
> +    interrupt any ongoing result set writer from storing data in an invalidated
> +    table thanks to the structure_guard_mutex.

Very confusing comment. Even though I know what happens in the
bugreport, how insert invalidation works in general and why it fails
here, and how your fix helps, I still have troubles understanding the
comment. Try to rewrite it please.

> +  */
> +  ulonglong actual_data_file_length;
> +  ulonglong current_data_file_length;
> +
> +  pthread_mutex_lock(&file->lock.lock->mutex);

As we discussed with Kostja, you don't need a mutex here.
You only want to see if actual_data_file_length !=
current_data_file_length, you don't care about the exact value of
actual_data_file_length. So, it's ok if you'll see garbage there because
of non-atomic update.

> +  actual_data_file_length= file->s->state.state.data_file_length;
> +  current_data_file_length= file->save_state.data_file_length;
> +  pthread_mutex_unlock(&file->lock.lock->mutex);
> +
> +  *engine_data= current_data_file_length;
> +
> +  if (current_data_file_length != actual_data_file_length)
> +  {
> +    /* Don't cache current statement. */
> +    return FALSE;
> +  }
> +
> +  /* It is ok to try to cache current statement. */
> +  return TRUE;
> +}
> +#endif
> 
Regards / Mit vielen Grüssen,
Sergei

-- 
   __  ___     ___ ____  __
  /  |/  /_ __/ __/ __ \/ /   Sergei Golubchik <serg@stripped>
 / /|_/ / // /\ \/ /_/ / /__  Principal Software Developer
/_/  /_/\_, /___/\___\_\___/  MySQL GmbH, Radlkoferstr. 2, D-81373 München
       <___/                  Geschäftsführer: Kaj Arnö - HRB
München 162140
Thread
bk commit into 5.0 tree (thek:1.2489) BUG#28249kpettersson9 Jul
  • Re: bk commit into 5.0 tree (thek:1.2489) BUG#28249Sergei Golubchik10 Jul
    • Re: bk commit into 5.0 tree (thek:1.2489) BUG#28249Kristofer Pettersson11 Jul