summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@oracle.com>2013-02-08 09:22:46 +0200
committerMarko Mäkelä <marko.makela@oracle.com>2013-02-08 09:22:46 +0200
commita6fb71e249f2b8e21f1c365e5acf531f6fd2577a (patch)
tree73d4d3a671e3965721b243dd706689b73ee51099 /storage
parentb7cfe73fa5f02dff4b92493e880161e27051dbdf (diff)
downloadmariadb-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.c39
-rw-r--r--storage/innodb_plugin/srv/srv0srv.c43
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 */