Below is the list of changes that have just been committed into a local
5.0 repository of thek. When thek does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-07-06 17:22:41+02:00, thek@adventure.(none) +3 -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 notice 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.
FOR PREVIEW STILL NEEDS TEST CASE
sql/ha_myisam.cc@stripped, 2007-07-06 17:22:40+02:00, thek@adventure.(none) +63 -0
- Implemented handler interface for ha_myisam class to dermine if the table
belonging to the currently processed statement can be cached or not.
sql/ha_myisam.h@stripped, 2007-07-06 17:22:40+02:00, thek@adventure.(none) +7 -0
- Implemented handler interface for ha_myisam class to dermine if the table
belonging to the currently processed statement can be cached or not.
sql/handler.h@stripped, 2007-07-06 17:22:40+02:00, thek@adventure.(none) +40 -6
- Documented register_query_cache_table method in the handler interface.
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: thek
# Host: adventure.(none)
# Root: /home/thek/Development/cpp/bug28249/my50-bug28249
--- 1.178/sql/ha_myisam.cc 2007-03-28 10:22:20 +02:00
+++ 1.179/sql/ha_myisam.cc 2007-07-06 17:22:40 +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 specific call
+ back function, currently 0
+ @param[out] engine_data The table size as seen by the current thread.
+
+ @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.
+ */
+ ulonglong actual_data_file_length;
+ ulonglong current_data_file_length;
+
+ pthread_mutex_lock(&file->lock.lock->mutex);
+ 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
--- 1.72/sql/ha_myisam.h 2006-12-30 21:02:06 +01:00
+++ 1.73/sql/ha_myisam.h 2007-07-06 17:22:40 +02:00
@@ -127,4 +127,11 @@ class ha_myisam: public handler
int dump(THD* thd, int fd);
int net_read_dump(NET* net);
#endif
+#ifdef HAVE_QUERY_CACHE
+ my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data);
+#endif
};
--- 1.183/sql/handler.h 2007-03-30 10:00:20 +02:00
+++ 1.184/sql/handler.h 2007-07-06 17:22:40 +02:00
@@ -841,16 +841,50 @@ public:
/* Type of table for caching query */
virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; }
- /* ask handler about permission to cache table when query is to be cached */
+
+
+ /**
+ @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 specific call
+ back function to be called on information retrieval
+ @param[out] engine_data Storage engine specific data which could be
+ anything
+
+ This method offers a storage engine to store a reference to a table name
+ which is to be used with query cache. It also offers the possibility to
+ register a generic (but static) call back function which is called each
+ time a statement is matched against the query cache.
+ The method is called on each time a statement is written to the cache and
+ can be used to verify if a specific statement is cachable.
+
+ @note If engine_data supplied with this function is different from
+ engine_data supplied with the callback function, this will implicate
+ a table invalidation on the current table if the callback returns
+ FALSE.
+
+ @return Upon success the engine_callback will point to the storage engine
+ call back function, if any, and engine_data will point to any storage
+ engine data used in the specific implementation.
+ @retval TRUE Success
+ @retval FALSE The specified table or current statement should not be
+ cached
+ */
+
virtual my_bool register_query_cache_table(THD *thd, char *table_key,
- uint key_length,
- qc_engine_callback
- *engine_callback,
- ulonglong *engine_data)
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
{
*engine_callback= 0;
- return 1;
+ return TRUE;
}
+
+
/*
RETURN
true Primary key (if there is one) is clustered key covering all fields
| Thread |
|---|
| • bk commit into 5.0 tree (thek:1.2489) BUG#28249 | kpettersson | 6 Jul |