1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file include/dict0stats.ic |
22 | Code used for calculating and manipulating table statistics. |
23 | |
24 | Created Jan 23, 2012 Vasil Dimov |
25 | *******************************************************/ |
26 | |
27 | #include "dict0dict.h" |
28 | #include "dict0types.h" |
29 | #include "srv0srv.h" |
30 | |
31 | /*********************************************************************//** |
32 | Set the persistent statistics flag for a given table. This is set only |
33 | in the in-memory table object and is not saved on disk. It will be read |
34 | from the .frm file upon first open from MySQL after a server restart. */ |
35 | UNIV_INLINE |
36 | void |
37 | dict_stats_set_persistent( |
38 | /*======================*/ |
39 | dict_table_t* table, /*!< in/out: table */ |
40 | ibool ps_on, /*!< in: persistent stats explicitly enabled */ |
41 | ibool ps_off) /*!< in: persistent stats explicitly disabled */ |
42 | { |
43 | /* Not allowed to have both flags set, but a CREATE or ALTER |
44 | statement that contains "STATS_PERSISTENT=0 STATS_PERSISTENT=1" would |
45 | end up having both set. In this case we clear the OFF flag. */ |
46 | if (ps_on && ps_off) { |
47 | ps_off = FALSE; |
48 | } |
49 | |
50 | ib_uint32_t stat_persistent = 0; |
51 | |
52 | if (ps_on) { |
53 | stat_persistent |= DICT_STATS_PERSISTENT_ON; |
54 | } |
55 | |
56 | if (ps_off) { |
57 | stat_persistent |= DICT_STATS_PERSISTENT_OFF; |
58 | } |
59 | |
60 | /* we rely on this assignment to be atomic */ |
61 | table->stat_persistent = stat_persistent; |
62 | } |
63 | |
64 | /** @return whether persistent statistics is enabled for a given table */ |
65 | UNIV_INLINE |
66 | bool |
67 | dict_stats_is_persistent_enabled(const dict_table_t* table) |
68 | { |
69 | /* Because of the nature of this check (non-locking) it is possible |
70 | that a table becomes: |
71 | * PS-disabled immediately after this function has returned TRUE or |
72 | * PS-enabled immediately after this function has returned FALSE. |
73 | This means that it is possible that we do: |
74 | + dict_stats_update(DICT_STATS_RECALC_PERSISTENT) on a table that has |
75 | just been PS-disabled or |
76 | + dict_stats_update(DICT_STATS_RECALC_TRANSIENT) on a table that has |
77 | just been PS-enabled. |
78 | This is acceptable. Avoiding this would mean that we would have to |
79 | protect the ::stat_persistent with dict_table_stats_lock() like the |
80 | other ::stat_ members which would be too big performance penalty, |
81 | especially when this function is called from |
82 | dict_stats_update_if_needed(). */ |
83 | |
84 | /* we rely on this read to be atomic */ |
85 | ib_uint32_t stat_persistent = table->stat_persistent; |
86 | |
87 | if (stat_persistent & DICT_STATS_PERSISTENT_ON) { |
88 | ut_ad(!(stat_persistent & DICT_STATS_PERSISTENT_OFF)); |
89 | return(true); |
90 | } else if (stat_persistent & DICT_STATS_PERSISTENT_OFF) { |
91 | return(false); |
92 | } else { |
93 | return(srv_stats_persistent); |
94 | } |
95 | } |
96 | |
97 | /*********************************************************************//** |
98 | Set the auto recalc flag for a given table (only honored for a persistent |
99 | stats enabled table). The flag is set only in the in-memory table object |
100 | and is not saved in InnoDB files. It will be read from the .frm file upon |
101 | first open from MySQL after a server restart. */ |
102 | UNIV_INLINE |
103 | void |
104 | dict_stats_auto_recalc_set( |
105 | /*=======================*/ |
106 | dict_table_t* table, /*!< in/out: table */ |
107 | ibool auto_recalc_on, /*!< in: explicitly enabled */ |
108 | ibool auto_recalc_off) /*!< in: explicitly disabled */ |
109 | { |
110 | ut_ad(!auto_recalc_on || !auto_recalc_off); |
111 | |
112 | ib_uint32_t stats_auto_recalc = 0; |
113 | |
114 | if (auto_recalc_on) { |
115 | stats_auto_recalc |= DICT_STATS_AUTO_RECALC_ON; |
116 | } |
117 | |
118 | if (auto_recalc_off) { |
119 | stats_auto_recalc |= DICT_STATS_AUTO_RECALC_OFF; |
120 | } |
121 | |
122 | /* we rely on this assignment to be atomic */ |
123 | table->stats_auto_recalc = stats_auto_recalc; |
124 | } |
125 | |
126 | /** @return whether auto recalc is enabled for a given table*/ |
127 | UNIV_INLINE |
128 | bool |
129 | dict_stats_auto_recalc_is_enabled(const dict_table_t* table) |
130 | { |
131 | /* we rely on this read to be atomic */ |
132 | ib_uint32_t stats_auto_recalc = table->stats_auto_recalc; |
133 | |
134 | if (stats_auto_recalc & DICT_STATS_AUTO_RECALC_ON) { |
135 | ut_ad(!(stats_auto_recalc & DICT_STATS_AUTO_RECALC_OFF)); |
136 | return(true); |
137 | } else if (stats_auto_recalc & DICT_STATS_AUTO_RECALC_OFF) { |
138 | return(false); |
139 | } else { |
140 | return(srv_stats_auto_recalc); |
141 | } |
142 | } |
143 | |
144 | /*********************************************************************//** |
145 | Initialize table's stats for the first time when opening a table. */ |
146 | UNIV_INLINE |
147 | void |
148 | dict_stats_init( |
149 | /*============*/ |
150 | dict_table_t* table) /*!< in/out: table */ |
151 | { |
152 | ut_ad(!mutex_own(&dict_sys->mutex)); |
153 | |
154 | if (table->stat_initialized) { |
155 | return; |
156 | } |
157 | |
158 | dict_stats_upd_option_t opt; |
159 | |
160 | if (dict_stats_is_persistent_enabled(table)) { |
161 | opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY; |
162 | } else { |
163 | opt = DICT_STATS_RECALC_TRANSIENT; |
164 | } |
165 | |
166 | dict_stats_update(table, opt); |
167 | } |
168 | |
169 | /*********************************************************************//** |
170 | Deinitialize table's stats after the last close of the table. This is |
171 | used to detect "FLUSH TABLE" and refresh the stats upon next open. */ |
172 | UNIV_INLINE |
173 | void |
174 | dict_stats_deinit( |
175 | /*==============*/ |
176 | dict_table_t* table) /*!< in/out: table */ |
177 | { |
178 | ut_ad(mutex_own(&dict_sys->mutex)); |
179 | |
180 | ut_a(table->get_ref_count() == 0); |
181 | |
182 | dict_table_stats_lock(table, RW_X_LATCH); |
183 | |
184 | if (!table->stat_initialized) { |
185 | dict_table_stats_unlock(table, RW_X_LATCH); |
186 | return; |
187 | } |
188 | |
189 | table->stat_initialized = FALSE; |
190 | |
191 | #ifdef UNIV_DEBUG_VALGRIND |
192 | UNIV_MEM_INVALID(&table->stat_n_rows, |
193 | sizeof(table->stat_n_rows)); |
194 | UNIV_MEM_INVALID(&table->stat_clustered_index_size, |
195 | sizeof(table->stat_clustered_index_size)); |
196 | UNIV_MEM_INVALID(&table->stat_sum_of_other_index_sizes, |
197 | sizeof(table->stat_sum_of_other_index_sizes)); |
198 | UNIV_MEM_INVALID(&table->stat_modified_counter, |
199 | sizeof(table->stat_modified_counter)); |
200 | |
201 | dict_index_t* index; |
202 | |
203 | for (index = dict_table_get_first_index(table); |
204 | index != NULL; |
205 | index = dict_table_get_next_index(index)) { |
206 | |
207 | ulint n_uniq = dict_index_get_n_unique(index); |
208 | |
209 | UNIV_MEM_INVALID( |
210 | index->stat_n_diff_key_vals, |
211 | n_uniq * sizeof(index->stat_n_diff_key_vals[0])); |
212 | UNIV_MEM_INVALID( |
213 | index->stat_n_sample_sizes, |
214 | n_uniq * sizeof(index->stat_n_sample_sizes[0])); |
215 | UNIV_MEM_INVALID( |
216 | index->stat_n_non_null_key_vals, |
217 | n_uniq * sizeof(index->stat_n_non_null_key_vals[0])); |
218 | UNIV_MEM_INVALID( |
219 | &index->stat_index_size, |
220 | sizeof(index->stat_index_size)); |
221 | UNIV_MEM_INVALID( |
222 | &index->stat_n_leaf_pages, |
223 | sizeof(index->stat_n_leaf_pages)); |
224 | } |
225 | #endif /* UNIV_DEBUG_VALGRIND */ |
226 | |
227 | dict_table_stats_unlock(table, RW_X_LATCH); |
228 | } |
229 | |