summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Vojtovich <svoj@sun.com>2010-04-14 13:53:59 +0400
committerSergey Vojtovich <svoj@sun.com>2010-04-14 13:53:59 +0400
commit4aa36ee7b689c4e9f74ccdc08fa278df66042fe8 (patch)
treeb63efe0cd130b6f27ed369fb7438cca073cabe69
parent6eca53f1d382a247456d29794c70338f972b77a9 (diff)
downloadmariadb-git-4aa36ee7b689c4e9f74ccdc08fa278df66042fe8.tar.gz
BUG#39053 - UNISTALL PLUGIN does not allow the storage engine
to cleanup open connections It was possible to UNINSTALL storage engine plugin when binding between THD object and storage engine is still active (e.g. in the middle of transaction). To avoid unclean deactivation (uninstall) of storage engine plugin in the middle of transaction, additional storage engine plugin lock is acquired by thd_set_ha_data(). If ha_data is not null and storage engine plugin was not locked by thd_set_ha_data() in this connection before, storage engine plugin gets locked. If ha_data is null and storage engine plugin was locked by thd_set_ha_data() in this connection before, storage engine plugin lock gets released. If handlerton::close_connection() didn't reset ha_data, server does it immediately after calling handlerton::close_connection(). Note that this is just a framework fix, storage engines must switch to thd_set_ha_data() from thd_ha_data() if they want to see fit. include/mysql/plugin.h: As thd_{get|set}_ha_data() have some extra logic now, they must be implemented on server side. include/mysql/plugin.h.pp: As thd_{get|set}_ha_data() have some extra logic now, they must be implemented on server side. sql/handler.cc: Make sure ha_data is reset and ha_data lock is released. sql/handler.h: hton is not supposed to be updated by ha_lock_engine(), make it const. sql/sql_class.cc: As thd_{get|set}_ha_data() have some extra logic now, they must be implemented on server side. sql/sql_class.h: Added ha_data lock.
-rw-r--r--include/mysql/plugin.h39
-rw-r--r--include/mysql/plugin.h.pp3
-rw-r--r--sql/handler.cc12
-rw-r--r--sql/handler.h2
-rw-r--r--sql/sql_class.cc31
-rw-r--r--sql/sql_class.h6
6 files changed, 71 insertions, 22 deletions
diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h
index 58b3848b85f..55ef6070f85 100644
--- a/include/mysql/plugin.h
+++ b/include/mysql/plugin.h
@@ -801,30 +801,37 @@ void mysql_query_cache_invalidate4(MYSQL_THD thd,
const char *key, unsigned int key_length,
int using_trx);
-#ifdef __cplusplus
-}
-#endif
-#ifdef __cplusplus
/**
Provide a handler data getter to simplify coding
*/
-inline
-void *
-thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton)
-{
- return *thd_ha_data(thd, hton);
-}
+void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton);
+
/**
Provide a handler data setter to simplify coding
+
+ @details
+ Set ha_data pointer (storage engine per-connection information).
+
+ To avoid unclean deactivation (uninstall) of storage engine plugin
+ in the middle of transaction, additional storage engine plugin
+ lock is acquired.
+
+ If ha_data is not null and storage engine plugin was not locked
+ by thd_set_ha_data() in this connection before, storage engine
+ plugin gets locked.
+
+ If ha_data is null and storage engine plugin was locked by
+ thd_set_ha_data() in this connection before, storage engine
+ plugin lock gets released.
+
+ If handlerton::close_connection() didn't reset ha_data, server does
+ it immediately after calling handlerton::close_connection().
*/
-inline
-void
-thd_set_ha_data(const MYSQL_THD thd, const struct handlerton *hton,
- const void *ha_data)
-{
- *thd_ha_data(thd, hton)= (void*) ha_data;
+void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton,
+ const void *ha_data);
+#ifdef __cplusplus
}
#endif
diff --git a/include/mysql/plugin.h.pp b/include/mysql/plugin.h.pp
index 50511f515ab..e4906ea6547 100644
--- a/include/mysql/plugin.h.pp
+++ b/include/mysql/plugin.h.pp
@@ -137,3 +137,6 @@ void thd_get_xid(const void* thd, MYSQL_XID *xid);
void mysql_query_cache_invalidate4(void* thd,
const char *key, unsigned int key_length,
int using_trx);
+void *thd_get_ha_data(const void* thd, const struct handlerton *hton);
+void thd_set_ha_data(void* thd, const struct handlerton *hton,
+ const void *ha_data);
diff --git a/sql/handler.cc b/sql/handler.cc
index 216228ed509..19f397ef09f 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -159,7 +159,7 @@ redo:
}
-plugin_ref ha_lock_engine(THD *thd, handlerton *hton)
+plugin_ref ha_lock_engine(THD *thd, const handlerton *hton)
{
if (hton)
{
@@ -601,9 +601,13 @@ static my_bool closecon_handlerton(THD *thd, plugin_ref plugin,
there's no need to rollback here as all transactions must
be rolled back already
*/
- if (hton->state == SHOW_OPTION_YES && hton->close_connection &&
- thd_get_ha_data(thd, hton))
- hton->close_connection(hton, thd);
+ if (hton->state == SHOW_OPTION_YES && thd_get_ha_data(thd, hton))
+ {
+ if (hton->close_connection)
+ hton->close_connection(hton, thd);
+ /* make sure ha_data is reset and ha_data_lock is released */
+ thd_set_ha_data(thd, hton, NULL);
+ }
return FALSE;
}
diff --git a/sql/handler.h b/sql/handler.h
index 7fc2bf2fece..d9dfd4f0707 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1956,7 +1956,7 @@ extern ulong total_ha, total_ha_2pc;
/* lookups */
handlerton *ha_default_handlerton(THD *thd);
plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
-plugin_ref ha_lock_engine(THD *thd, handlerton *hton);
+plugin_ref ha_lock_engine(THD *thd, const handlerton *hton);
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type);
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
handlerton *db_type);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 266064f9f08..bf5af7141c0 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -284,6 +284,37 @@ void **thd_ha_data(const THD *thd, const struct handlerton *hton)
return (void **) &thd->ha_data[hton->slot].ha_ptr;
}
+
+/**
+ Provide a handler data getter to simplify coding
+*/
+extern "C"
+void *thd_get_ha_data(const THD *thd, const struct handlerton *hton)
+{
+ return *thd_ha_data(thd, hton);
+}
+
+
+/**
+ Provide a handler data setter to simplify coding
+ @see thd_set_ha_data() definition in plugin.h
+*/
+extern "C"
+void thd_set_ha_data(THD *thd, const struct handlerton *hton,
+ const void *ha_data)
+{
+ plugin_ref *lock= &thd->ha_data[hton->slot].lock;
+ if (ha_data && !*lock)
+ *lock= ha_lock_engine(NULL, (handlerton*) hton);
+ else if (!ha_data && *lock)
+ {
+ plugin_unlock(NULL, *lock);
+ *lock= NULL;
+ }
+ *thd_ha_data(thd, hton)= (void*) ha_data;
+}
+
+
extern "C"
long long thd_test_options(const THD *thd, long long test_options)
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2ddd9358382..4d0552c5b9d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1264,7 +1264,11 @@ struct Ha_data
@sa trans_register_ha()
*/
Ha_trx_info ha_info[2];
-
+ /**
+ NULL: engine is not bound to this thread
+ non-NULL: engine is bound to this thread, engine shutdown forbidden
+ */
+ plugin_ref lock;
Ha_data() :ha_ptr(NULL) {}
};