MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
dict0stats_bg.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "row0mysql.h"
27 #include "srv0start.h"
28 #include "dict0stats.h"
29 #include "dict0stats_bg.h"
30 
31 #ifdef UNIV_NONINL
32 # include "dict0stats_bg.ic"
33 #endif
34 
35 #include <vector>
36 
38 #define MIN_RECALC_INTERVAL 10 /* seconds */
39 
40 #define SHUTTING_DOWN() (srv_shutdown_state != SRV_SHUTDOWN_NONE)
41 
43 UNIV_INTERN os_event_t dict_stats_event = NULL;
44 
46 static ib_mutex_t recalc_pool_mutex;
47 #ifdef HAVE_PSI_INTERFACE
48 static mysql_pfs_key_t recalc_pool_mutex_key;
49 #endif /* HAVE_PSI_INTERFACE */
50 
53 static const ulint RECALC_POOL_INITIAL_SLOTS = 128;
54 
57 typedef std::vector<table_id_t> recalc_pool_t;
58 static recalc_pool_t recalc_pool;
59 
60 typedef recalc_pool_t::iterator recalc_pool_iterator_t;
61 
62 /*****************************************************************/
64 static
65 void
66 dict_stats_recalc_pool_init()
67 /*=========================*/
68 {
70 
71  recalc_pool.reserve(RECALC_POOL_INITIAL_SLOTS);
72 }
73 
74 /*****************************************************************/
77 static
78 void
79 dict_stats_recalc_pool_deinit()
80 /*===========================*/
81 {
83 
84  recalc_pool.clear();
85 }
86 
87 /*****************************************************************/
93 UNIV_INTERN
94 void
96 /*=======================*/
97  const dict_table_t* table)
98 {
100 
101  mutex_enter(&recalc_pool_mutex);
102 
103  /* quit if already in the list */
104  for (recalc_pool_iterator_t iter = recalc_pool.begin();
105  iter != recalc_pool.end();
106  ++iter) {
107 
108  if (*iter == table->id) {
109  mutex_exit(&recalc_pool_mutex);
110  return;
111  }
112  }
113 
114  recalc_pool.push_back(table->id);
115 
116  mutex_exit(&recalc_pool_mutex);
117 
119 }
120 
121 /*****************************************************************/
125 static
126 bool
127 dict_stats_recalc_pool_get(
128 /*=======================*/
129  table_id_t* id)
131 {
133 
134  mutex_enter(&recalc_pool_mutex);
135 
136  if (recalc_pool.empty()) {
137  mutex_exit(&recalc_pool_mutex);
138  return(false);
139  }
140 
141  *id = recalc_pool[0];
142 
143  recalc_pool.erase(recalc_pool.begin());
144 
145  mutex_exit(&recalc_pool_mutex);
146 
147  return(true);
148 }
149 
150 /*****************************************************************/
153 UNIV_INTERN
154 void
156 /*=======================*/
157  const dict_table_t* table)
158 {
160  ut_ad(mutex_own(&dict_sys->mutex));
161 
162  mutex_enter(&recalc_pool_mutex);
163 
164  ut_ad(table->id > 0);
165 
166  for (recalc_pool_iterator_t iter = recalc_pool.begin();
167  iter != recalc_pool.end();
168  ++iter) {
169 
170  if (*iter == table->id) {
171  /* erase() invalidates the iterator */
172  recalc_pool.erase(iter);
173  break;
174  }
175  }
176 
177  mutex_exit(&recalc_pool_mutex);
178 }
179 
180 /*****************************************************************/
189 UNIV_INTERN
190 void
192 /*===================================*/
194  trx_t* trx)
196 {
197  while (!dict_stats_stop_bg(table)) {
198  DICT_STATS_BG_YIELD(trx);
199  }
200 }
201 
202 /*****************************************************************/
205 UNIV_INTERN
206 void
208 /*====================*/
209 {
211 
213 
214  /* The recalc_pool_mutex is acquired from:
215  1) the background stats gathering thread before any other latch
216  and released without latching anything else in between (thus
217  any level would do here)
218  2) from row_update_statistics_if_needed()
219  and released without latching anything else in between. We know
220  that dict_sys->mutex (SYNC_DICT) is not acquired when
221  row_update_statistics_if_needed() is called and it may be acquired
222  inside that function (thus a level <=SYNC_DICT would do).
223  3) from row_drop_table_for_mysql() after dict_sys->mutex (SYNC_DICT)
224  and dict_operation_lock (SYNC_DICT_OPERATION) have been locked
225  (thus a level <SYNC_DICT && <SYNC_DICT_OPERATION would do)
226  So we choose SYNC_STATS_AUTO_RECALC to be about below SYNC_DICT. */
227  mutex_create(recalc_pool_mutex_key, &recalc_pool_mutex,
228  SYNC_STATS_AUTO_RECALC);
229 
230  dict_stats_recalc_pool_init();
231 }
232 
233 /*****************************************************************/
236 UNIV_INTERN
237 void
239 /*======================*/
240 {
242  ut_ad(!srv_dict_stats_thread_active);
243 
244  dict_stats_recalc_pool_deinit();
245 
246  mutex_free(&recalc_pool_mutex);
247  memset(&recalc_pool_mutex, 0x0, sizeof(recalc_pool_mutex));
248 
250  dict_stats_event = NULL;
251 }
252 
253 /*****************************************************************/
256 static
257 void
258 dict_stats_process_entry_from_recalc_pool()
259 /*=======================================*/
260 {
261  table_id_t table_id;
262 
264 
265  /* pop the first table from the auto recalc pool */
266  if (!dict_stats_recalc_pool_get(&table_id)) {
267  /* no tables for auto recalc */
268  return;
269  }
270 
272 
273  mutex_enter(&dict_sys->mutex);
274 
275  table = dict_table_open_on_id(table_id, TRUE, DICT_TABLE_OP_NORMAL);
276 
277  if (table == NULL) {
278  /* table does not exist, must have been DROPped
279  after its id was enqueued */
280  mutex_exit(&dict_sys->mutex);
281  return;
282  }
283 
284  /* Check whether table is corrupted */
285  if (table->corrupted) {
286  dict_table_close(table, TRUE, FALSE);
287  mutex_exit(&dict_sys->mutex);
288  return;
289  }
290 
292 
293  mutex_exit(&dict_sys->mutex);
294 
295  /* ut_time() could be expensive, the current function
296  is called once every time a table has been changed more than 10% and
297  on a system with lots of small tables, this could become hot. If we
298  find out that this is a problem, then the check below could eventually
299  be replaced with something else, though a time interval is the natural
300  approach. */
301 
302  if (ut_difftime(ut_time(), table->stats_last_recalc)
304 
305  /* Stats were (re)calculated not long ago. To avoid
306  too frequent stats updates we put back the table on
307  the auto recalc list and do nothing. */
308 
310 
311  } else {
312 
313  dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT);
314  }
315 
316  mutex_enter(&dict_sys->mutex);
317 
318  table->stats_bg_flag = BG_STAT_NONE;
319 
320  dict_table_close(table, TRUE, FALSE);
321 
322  mutex_exit(&dict_sys->mutex);
323 }
324 
325 /*****************************************************************/
330 extern "C" UNIV_INTERN
331 os_thread_ret_t
333 /*==============================*/
334  void* arg __attribute__((unused)))
336 {
338 
339  srv_dict_stats_thread_active = TRUE;
340 
341  while (!SHUTTING_DOWN()) {
342 
343  /* Wake up periodically even if not signaled. This is
344  because we may lose an event - if the below call to
345  dict_stats_process_entry_from_recalc_pool() puts the entry back
346  in the list, the os_event_set() will be lost by the subsequent
347  os_event_reset(). */
348  os_event_wait_time(
350 
351  if (SHUTTING_DOWN()) {
352  break;
353  }
354 
355  dict_stats_process_entry_from_recalc_pool();
356 
358  }
359 
360  srv_dict_stats_thread_active = FALSE;
361 
362  /* We count the number of threads in os_thread_exit(). A created
363  thread should always use that to exit instead of return(). */
364  os_thread_exit(NULL);
365 
366  OS_THREAD_DUMMY_RETURN;
367 }