diff options
author | Marko Mäkelä <marko.makela@oracle.com> | 2013-02-08 09:22:46 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@oracle.com> | 2013-02-08 09:22:46 +0200 |
commit | a6fb71e249f2b8e21f1c365e5acf531f6fd2577a (patch) | |
tree | 73d4d3a671e3965721b243dd706689b73ee51099 /storage | |
parent | b7cfe73fa5f02dff4b92493e880161e27051dbdf (diff) | |
download | mariadb-git-a6fb71e249f2b8e21f1c365e5acf531f6fd2577a.tar.gz |
Bug#16292043 RACE CONDITION IN SRV_EXPORT_INNODB_STATUS() WHEN ACCESSING PURGE_SYS->VIEW
srv_export_innodb_status(): Read the purge_sys fields while holding
purge_sys->latch.
Approved by Sunny Bains
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/srv/srv0srv.c | 39 | ||||
-rw-r--r-- | storage/innodb_plugin/srv/srv0srv.c | 43 |
2 files changed, 52 insertions, 30 deletions
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 3240b7515f8..e5619abbe45 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -1922,21 +1922,32 @@ srv_export_innodb_status(void) export_vars.innodb_rows_deleted = srv_n_rows_deleted; #ifdef UNIV_DEBUG - if (ut_dulint_cmp(trx_sys->max_trx_id, purge_sys->done_trx_no) < 0) { - export_vars.innodb_purge_trx_id_age = 0; - } else { - export_vars.innodb_purge_trx_id_age = - ut_dulint_minus(trx_sys->max_trx_id, purge_sys->done_trx_no); - } + { + dulint done_trx_no; + dulint up_limit_id; + + rw_lock_s_lock(&purge_sys->latch); + done_trx_no = purge_sys->done_trx_no; + up_limit_id = purge_sys->view + ? purge_sys->view->up_limit_id + : ut_dulint_zero; + rw_lock_s_unlock(&purge_sys->latch); + + if (ut_dulint_cmp(trx_sys->max_trx_id, done_trx_no) < 0) { + export_vars.innodb_purge_trx_id_age = 0; + } else { + export_vars.innodb_purge_trx_id_age = ut_dulint_minus( + trx_sys->max_trx_id, done_trx_no); + } - if (!purge_sys->view - || ut_dulint_cmp(trx_sys->max_trx_id, - purge_sys->view->up_limit_id) < 0) { - export_vars.innodb_purge_view_trx_id_age = 0; - } else { - export_vars.innodb_purge_view_trx_id_age = - ut_dulint_minus(trx_sys->max_trx_id, - purge_sys->view->up_limit_id); + if (ut_dulint_is_zero(up_limit_id) + || ut_dulint_cmp(trx_sys->max_trx_id, up_limit_id) < 0) { + export_vars.innodb_purge_view_trx_id_age = 0; + } else { + export_vars.innodb_purge_view_trx_id_age = + ut_dulint_minus(trx_sys->max_trx_id, + up_limit_id); + } } #endif /* UNIV_DEBUG */ diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index 4ddd0a4603d..4e626003f4f 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. @@ -257,7 +257,7 @@ UNIV_INTERN ulint srv_data_read = 0; /* Internal setting for "innodb_stats_method". Decides how InnoDB treats NULL value when collecting statistics. By default, it is set to SRV_STATS_NULLS_EQUAL(0), ie. all NULL value are treated equal */ -ulong srv_innodb_stats_method = SRV_STATS_NULLS_EQUAL; +UNIV_INTERN ulong srv_innodb_stats_method = SRV_STATS_NULLS_EQUAL; /* here we count the amount of data written in total (in bytes) */ UNIV_INTERN ulint srv_data_written = 0; @@ -1978,21 +1978,32 @@ srv_export_innodb_status(void) export_vars.innodb_rows_deleted = srv_n_rows_deleted; #ifdef UNIV_DEBUG - if (ut_dulint_cmp(trx_sys->max_trx_id, purge_sys->done_trx_no) < 0) { - export_vars.innodb_purge_trx_id_age = 0; - } else { - export_vars.innodb_purge_trx_id_age = - ut_dulint_minus(trx_sys->max_trx_id, purge_sys->done_trx_no); - } + { + dulint done_trx_no; + dulint up_limit_id; + + rw_lock_s_lock(&purge_sys->latch); + done_trx_no = purge_sys->done_trx_no; + up_limit_id = purge_sys->view + ? purge_sys->view->up_limit_id + : ut_dulint_zero; + rw_lock_s_unlock(&purge_sys->latch); + + if (ut_dulint_cmp(trx_sys->max_trx_id, done_trx_no) < 0) { + export_vars.innodb_purge_trx_id_age = 0; + } else { + export_vars.innodb_purge_trx_id_age = ut_dulint_minus( + trx_sys->max_trx_id, done_trx_no); + } - if (!purge_sys->view - || ut_dulint_cmp(trx_sys->max_trx_id, - purge_sys->view->up_limit_id) < 0) { - export_vars.innodb_purge_view_trx_id_age = 0; - } else { - export_vars.innodb_purge_view_trx_id_age = - ut_dulint_minus(trx_sys->max_trx_id, - purge_sys->view->up_limit_id); + if (ut_dulint_is_zero(up_limit_id) + || ut_dulint_cmp(trx_sys->max_trx_id, up_limit_id) < 0) { + export_vars.innodb_purge_view_trx_id_age = 0; + } else { + export_vars.innodb_purge_view_trx_id_age = + ut_dulint_minus(trx_sys->max_trx_id, + up_limit_id); + } } #endif /* UNIV_DEBUG */ |