]>
Commit | Line | Data |
---|---|---|
b4e1fa2c AM |
1 | # name : innodb_stats.patch |
2 | # introduced : 11 or before | |
3 | # maintainer : Yasufumi | |
4 | # | |
5 | #!!! notice !!! | |
6 | # Any small change to this file in the main branch | |
7 | # should be done or reviewed by the maintainer! | |
b4e1fa2c AM |
8 | diff -ruN a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c |
9 | --- a/storage/innobase/dict/dict0boot.c 2010-12-03 15:48:03.034036843 +0900 | |
10 | +++ b/storage/innobase/dict/dict0boot.c 2010-12-03 17:19:24.835112632 +0900 | |
11 | @@ -266,6 +266,29 @@ | |
12 | /* Get the dictionary header */ | |
13 | dict_hdr = dict_hdr_get(&mtr); | |
14 | ||
15 | + if (mach_read_from_8(dict_hdr + DICT_HDR_XTRADB_MARK) | |
16 | + != DICT_HDR_XTRADB_FLAG) { | |
17 | + /* not extended yet by XtraDB, need to be extended */ | |
18 | + ulint root_page_no; | |
19 | + | |
20 | + root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, | |
21 | + DICT_HDR_SPACE, 0, DICT_STATS_ID, | |
22 | + dict_ind_redundant, &mtr); | |
23 | + if (root_page_no == FIL_NULL) { | |
24 | + fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n"); | |
25 | + srv_use_sys_stats_table = FALSE; | |
26 | + } else { | |
27 | + mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no, | |
28 | + MLOG_4BYTES, &mtr); | |
29 | + mlog_write_ull(dict_hdr + DICT_HDR_XTRADB_MARK, | |
30 | + DICT_HDR_XTRADB_FLAG, &mtr); | |
31 | + } | |
32 | + mtr_commit(&mtr); | |
33 | + /* restart mtr */ | |
34 | + mtr_start(&mtr); | |
35 | + dict_hdr = dict_hdr_get(&mtr); | |
36 | + } | |
37 | + | |
38 | /* Because we only write new row ids to disk-based data structure | |
39 | (dictionary header) when it is divisible by | |
40 | DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover | |
41 | @@ -425,7 +448,7 @@ | |
42 | table->id = DICT_FIELDS_ID; | |
43 | dict_table_add_to_cache(table, heap); | |
44 | dict_sys->sys_fields = table; | |
45 | - mem_heap_free(heap); | |
46 | + mem_heap_empty(heap); | |
47 | ||
48 | index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND", | |
49 | DICT_HDR_SPACE, | |
50 | @@ -442,6 +465,41 @@ | |
51 | FALSE); | |
52 | ut_a(error == DB_SUCCESS); | |
53 | ||
54 | + /*-------------------------*/ | |
55 | + table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 3, 0); | |
56 | + table->n_mysql_handles_opened = 1; /* for pin */ | |
57 | + | |
58 | + dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0); | |
59 | + dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4); | |
60 | + dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0); | |
61 | + | |
62 | + /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */ | |
63 | +#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2 | |
64 | +#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2" | |
65 | +#endif | |
66 | + | |
67 | + table->id = DICT_STATS_ID; | |
68 | + dict_table_add_to_cache(table, heap); | |
69 | + dict_sys->sys_stats = table; | |
70 | + mem_heap_empty(heap); | |
71 | + | |
72 | + index = dict_mem_index_create("SYS_STATS", "CLUST_IND", | |
73 | + DICT_HDR_SPACE, | |
74 | + DICT_UNIQUE | DICT_CLUSTERED, 2); | |
75 | + | |
76 | + dict_mem_index_add_field(index, "INDEX_ID", 0); | |
77 | + dict_mem_index_add_field(index, "KEY_COLS", 0); | |
78 | + | |
79 | + index->id = DICT_STATS_ID; | |
80 | + error = dict_index_add_to_cache(table, index, | |
81 | + mtr_read_ulint(dict_hdr | |
82 | + + DICT_HDR_STATS, | |
83 | + MLOG_4BYTES, &mtr), | |
84 | + FALSE); | |
85 | + ut_a(error == DB_SUCCESS); | |
86 | + | |
87 | + mem_heap_free(heap); | |
88 | + | |
89 | mtr_commit(&mtr); | |
90 | /*-------------------------*/ | |
91 | ||
92 | @@ -455,6 +513,7 @@ | |
93 | dict_load_sys_table(dict_sys->sys_columns); | |
94 | dict_load_sys_table(dict_sys->sys_indexes); | |
95 | dict_load_sys_table(dict_sys->sys_fields); | |
96 | + dict_load_sys_table(dict_sys->sys_stats); | |
97 | ||
98 | mutex_exit(&(dict_sys->mutex)); | |
99 | } | |
100 | diff -ruN a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c | |
101 | --- a/storage/innobase/dict/dict0crea.c 2010-12-03 15:48:03.036081059 +0900 | |
102 | +++ b/storage/innobase/dict/dict0crea.c 2010-12-03 17:19:24.836964976 +0900 | |
103 | @@ -508,6 +508,51 @@ | |
104 | } | |
105 | ||
106 | /*****************************************************************//** | |
107 | +Based on an index object, this function builds the entry to be inserted | |
108 | +in the SYS_STATS system table. | |
109 | +@return the tuple which should be inserted */ | |
110 | +static | |
111 | +dtuple_t* | |
112 | +dict_create_sys_stats_tuple( | |
113 | +/*========================*/ | |
114 | + const dict_index_t* index, | |
115 | + ulint i, | |
116 | + mem_heap_t* heap) | |
117 | +{ | |
118 | + dict_table_t* sys_stats; | |
119 | + dtuple_t* entry; | |
120 | + dfield_t* dfield; | |
121 | + byte* ptr; | |
122 | + | |
123 | + ut_ad(index); | |
124 | + ut_ad(heap); | |
125 | + | |
126 | + sys_stats = dict_sys->sys_stats; | |
127 | + | |
128 | + entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS); | |
129 | + | |
130 | + dict_table_copy_types(entry, sys_stats); | |
131 | + | |
132 | + /* 0: INDEX_ID -----------------------*/ | |
133 | + dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/); | |
134 | + ptr = mem_heap_alloc(heap, 8); | |
135 | + mach_write_to_8(ptr, index->id); | |
136 | + dfield_set_data(dfield, ptr, 8); | |
137 | + /* 1: KEY_COLS -----------------------*/ | |
138 | + dfield = dtuple_get_nth_field(entry, 1/*KEY_COLS*/); | |
139 | + ptr = mem_heap_alloc(heap, 4); | |
140 | + mach_write_to_4(ptr, i); | |
141 | + dfield_set_data(dfield, ptr, 4); | |
142 | + /* 4: DIFF_VALS ----------------------*/ | |
143 | + dfield = dtuple_get_nth_field(entry, 2/*DIFF_VALS*/); | |
144 | + ptr = mem_heap_alloc(heap, 8); | |
145 | + mach_write_to_8(ptr, 0); /* initial value is 0 */ | |
146 | + dfield_set_data(dfield, ptr, 8); | |
147 | + | |
148 | + return(entry); | |
149 | +} | |
150 | + | |
151 | +/*****************************************************************//** | |
152 | Creates the tuple with which the index entry is searched for writing the index | |
153 | tree root page number, if such a tree is created. | |
154 | @return the tuple for search */ | |
155 | @@ -617,6 +662,27 @@ | |
156 | } | |
157 | ||
158 | /***************************************************************//** | |
159 | +Builds a row for storing stats to insert. | |
160 | +@return DB_SUCCESS */ | |
161 | +static | |
162 | +ulint | |
163 | +dict_build_stats_def_step( | |
164 | +/*======================*/ | |
165 | + ind_node_t* node) | |
166 | +{ | |
167 | + dict_index_t* index; | |
168 | + dtuple_t* row; | |
169 | + | |
170 | + index = node->index; | |
171 | + | |
172 | + row = dict_create_sys_stats_tuple(index, node->stats_no, node->heap); | |
173 | + | |
174 | + ins_node_set_new_row(node->stats_def, row); | |
175 | + | |
176 | + return(DB_SUCCESS); | |
177 | +} | |
178 | + | |
179 | +/***************************************************************//** | |
180 | Creates an index tree for the index if it is not a member of a cluster. | |
181 | @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ | |
182 | static | |
183 | @@ -937,6 +1003,49 @@ | |
184 | dict_sys->sys_fields, heap); | |
185 | node->field_def->common.parent = node; | |
186 | ||
187 | + if (srv_use_sys_stats_table) { | |
188 | + node->stats_def = ins_node_create(INS_DIRECT, | |
189 | + dict_sys->sys_stats, heap); | |
190 | + node->stats_def->common.parent = node; | |
191 | + } else { | |
192 | + node->stats_def = NULL; | |
193 | + } | |
194 | + | |
195 | + node->commit_node = commit_node_create(heap); | |
196 | + node->commit_node->common.parent = node; | |
197 | + | |
198 | + return(node); | |
199 | +} | |
200 | + | |
201 | +/*********************************************************************//** | |
202 | +*/ | |
203 | +UNIV_INTERN | |
204 | +ind_node_t* | |
205 | +ind_insert_stats_graph_create( | |
206 | +/*==========================*/ | |
207 | + dict_index_t* index, | |
208 | + mem_heap_t* heap) | |
209 | +{ | |
210 | + ind_node_t* node; | |
211 | + | |
212 | + node = mem_heap_alloc(heap, sizeof(ind_node_t)); | |
213 | + | |
214 | + node->common.type = QUE_NODE_INSERT_STATS; | |
215 | + | |
216 | + node->index = index; | |
217 | + | |
218 | + node->state = INDEX_BUILD_STATS_COLS; | |
219 | + node->page_no = FIL_NULL; | |
220 | + node->heap = mem_heap_create(256); | |
221 | + | |
222 | + node->ind_def = NULL; | |
223 | + node->field_def = NULL; | |
224 | + | |
225 | + node->stats_def = ins_node_create(INS_DIRECT, | |
226 | + dict_sys->sys_stats, heap); | |
227 | + node->stats_def->common.parent = node; | |
228 | + node->stats_no = 0; | |
229 | + | |
230 | node->commit_node = commit_node_create(heap); | |
231 | node->commit_node->common.parent = node; | |
232 | ||
233 | @@ -1087,6 +1196,7 @@ | |
234 | ||
235 | node->state = INDEX_BUILD_FIELD_DEF; | |
236 | node->field_no = 0; | |
237 | + node->stats_no = 0; | |
238 | ||
239 | thr->run_node = node->ind_def; | |
240 | ||
241 | @@ -1132,7 +1242,31 @@ | |
242 | goto function_exit; | |
243 | } | |
244 | ||
245 | - node->state = INDEX_CREATE_INDEX_TREE; | |
246 | + if (srv_use_sys_stats_table | |
247 | + && !((node->table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) { | |
248 | + node->state = INDEX_BUILD_STATS_COLS; | |
249 | + } else { | |
250 | + node->state = INDEX_CREATE_INDEX_TREE; | |
251 | + } | |
252 | + } | |
253 | + if (node->state == INDEX_BUILD_STATS_COLS) { | |
254 | + if (node->stats_no <= dict_index_get_n_unique(node->index)) { | |
255 | + | |
256 | + err = dict_build_stats_def_step(node); | |
257 | + | |
258 | + if (err != DB_SUCCESS) { | |
259 | + | |
260 | + goto function_exit; | |
261 | + } | |
262 | + | |
263 | + node->stats_no++; | |
264 | + | |
265 | + thr->run_node = node->stats_def; | |
266 | + | |
267 | + return(thr); | |
268 | + } else { | |
269 | + node->state = INDEX_CREATE_INDEX_TREE; | |
270 | + } | |
271 | } | |
272 | ||
273 | if (node->state == INDEX_CREATE_INDEX_TREE) { | |
274 | @@ -1178,6 +1312,66 @@ | |
275 | return(NULL); | |
276 | } | |
277 | ||
278 | + thr->run_node = que_node_get_parent(node); | |
279 | + | |
280 | + return(thr); | |
281 | +} | |
282 | + | |
283 | +/****************************************************************//** | |
284 | +*/ | |
285 | +UNIV_INTERN | |
286 | +que_thr_t* | |
287 | +dict_insert_stats_step( | |
288 | +/*===================*/ | |
289 | + que_thr_t* thr) /*!< in: query thread */ | |
290 | +{ | |
291 | + ind_node_t* node; | |
292 | + ulint err = DB_ERROR; | |
293 | + trx_t* trx; | |
294 | + | |
295 | + ut_ad(thr); | |
296 | + | |
297 | + trx = thr_get_trx(thr); | |
298 | + | |
299 | + node = thr->run_node; | |
300 | + | |
301 | + if (thr->prev_node == que_node_get_parent(node)) { | |
302 | + node->state = INDEX_BUILD_STATS_COLS; | |
303 | + } | |
304 | + | |
305 | + if (node->state == INDEX_BUILD_STATS_COLS) { | |
306 | + if (node->stats_no <= dict_index_get_n_unique(node->index)) { | |
307 | + | |
308 | + err = dict_build_stats_def_step(node); | |
309 | + | |
310 | + if (err != DB_SUCCESS) { | |
311 | + | |
312 | + goto function_exit; | |
313 | + } | |
314 | + | |
315 | + node->stats_no++; | |
316 | + | |
317 | + thr->run_node = node->stats_def; | |
318 | + | |
319 | + return(thr); | |
320 | + } else { | |
321 | + node->state = INDEX_COMMIT_WORK; | |
322 | + } | |
323 | + } | |
324 | + | |
325 | + if (node->state == INDEX_COMMIT_WORK) { | |
326 | + | |
327 | + /* do not commit transaction here for now */ | |
328 | + } | |
329 | + | |
330 | +function_exit: | |
331 | + trx->error_state = err; | |
332 | + | |
333 | + if (err == DB_SUCCESS) { | |
334 | + } else { | |
335 | + return(NULL); | |
336 | + } | |
337 | + | |
338 | thr->run_node = que_node_get_parent(node); | |
339 | ||
340 | return(thr); | |
341 | diff -ruN a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c | |
342 | --- a/storage/innobase/dict/dict0dict.c 2010-12-03 15:48:03.040222428 +0900 | |
343 | +++ b/storage/innobase/dict/dict0dict.c 2010-12-03 17:19:24.841947690 +0900 | |
d8778560 | 344 | @@ -756,7 +756,7 @@ |
b4e1fa2c AM |
345 | print an error message and return without doing |
346 | anything. */ | |
347 | dict_update_statistics(table, TRUE /* only update stats | |
348 | - if they have not been initialized */); | |
349 | + if they have not been initialized */, FALSE); | |
350 | } | |
351 | ||
352 | return(table); | |
df1b5770 | 353 | @@ -4310,6 +4310,240 @@ |
b4e1fa2c AM |
354 | } |
355 | ||
356 | /*********************************************************************//** | |
357 | +functions to use SYS_STATS system table. */ | |
358 | +static | |
359 | +ibool | |
360 | +dict_reload_statistics( | |
361 | +/*===================*/ | |
362 | + dict_table_t* table, | |
363 | + ulint* sum_of_index_sizes) | |
364 | +{ | |
365 | + dict_index_t* index; | |
366 | + ulint size; | |
367 | + mem_heap_t* heap; | |
368 | + | |
369 | + index = dict_table_get_first_index(table); | |
370 | + | |
371 | + if (index == NULL) { | |
372 | + /* Table definition is corrupt */ | |
373 | + | |
374 | + return(FALSE); | |
375 | + } | |
376 | + | |
377 | + heap = mem_heap_create(1000); | |
378 | + | |
379 | + while (index) { | |
380 | + size = btr_get_size(index, BTR_TOTAL_SIZE); | |
381 | + | |
382 | + index->stat_index_size = size; | |
383 | + | |
384 | + *sum_of_index_sizes += size; | |
385 | + | |
386 | + size = btr_get_size(index, BTR_N_LEAF_PAGES); | |
387 | + | |
388 | + if (size == 0) { | |
389 | + /* The root node of the tree is a leaf */ | |
390 | + size = 1; | |
391 | + } | |
392 | + | |
393 | + index->stat_n_leaf_pages = size; | |
394 | + | |
395 | +/*===========================================*/ | |
396 | +{ | |
397 | + dict_table_t* sys_stats; | |
398 | + dict_index_t* sys_index; | |
399 | + btr_pcur_t pcur; | |
400 | + dtuple_t* tuple; | |
401 | + dfield_t* dfield; | |
402 | + ulint key_cols; | |
403 | + ulint n_cols; | |
404 | + const rec_t* rec; | |
405 | + const byte* field; | |
406 | + ulint len; | |
407 | + ib_int64_t* stat_n_diff_key_vals_tmp; | |
408 | + byte* buf; | |
409 | + ulint i; | |
410 | + mtr_t mtr; | |
411 | + | |
412 | + n_cols = dict_index_get_n_unique(index); | |
413 | + stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t)); | |
414 | + | |
415 | + sys_stats = dict_sys->sys_stats; | |
416 | + sys_index = UT_LIST_GET_FIRST(sys_stats->indexes); | |
417 | + ut_a(!dict_table_is_comp(sys_stats)); | |
418 | + | |
419 | + tuple = dtuple_create(heap, 1); | |
420 | + dfield = dtuple_get_nth_field(tuple, 0); | |
421 | + | |
422 | + buf = mem_heap_alloc(heap, 8); | |
423 | + mach_write_to_8(buf, index->id); | |
424 | + | |
425 | + dfield_set_data(dfield, buf, 8); | |
426 | + dict_index_copy_types(tuple, sys_index, 1); | |
427 | + | |
428 | + mtr_start(&mtr); | |
429 | + | |
430 | + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, | |
431 | + BTR_SEARCH_LEAF, &pcur, &mtr); | |
432 | + for (i = 0; i <= n_cols; i++) { | |
433 | + rec = btr_pcur_get_rec(&pcur); | |
434 | + | |
435 | + if (!btr_pcur_is_on_user_rec(&pcur) | |
436 | + || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len)) | |
437 | + != index->id) { | |
438 | + /* not found: even 1 if not found should not be alowed */ | |
439 | + fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)" | |
d8778560 | 440 | + " not found in SYS_STATS\n", |
b4e1fa2c AM |
441 | + index->table_name, index->name, i, n_cols); |
442 | + btr_pcur_close(&pcur); | |
443 | + mtr_commit(&mtr); | |
444 | + mem_heap_free(heap); | |
445 | + return(FALSE); | |
446 | + } | |
447 | + | |
448 | + if (rec_get_deleted_flag(rec, 0)) { | |
449 | + goto next_rec; | |
450 | + } | |
451 | + | |
452 | + field = rec_get_nth_field_old(rec, 1, &len); | |
453 | + ut_a(len == 4); | |
454 | + | |
455 | + key_cols = mach_read_from_4(field); | |
456 | + | |
457 | + ut_a(i == key_cols); | |
458 | + | |
459 | + field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len); | |
460 | + ut_a(len == 8); | |
461 | + | |
462 | + stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field); | |
463 | +next_rec: | |
464 | + btr_pcur_move_to_next_user_rec(&pcur, &mtr); | |
465 | + } | |
466 | + | |
467 | + btr_pcur_close(&pcur); | |
468 | + mtr_commit(&mtr); | |
469 | + | |
470 | + for (i = 0; i <= n_cols; i++) { | |
471 | + index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i]; | |
472 | + } | |
473 | +} | |
474 | +/*===========================================*/ | |
475 | + | |
476 | + index = dict_table_get_next_index(index); | |
477 | + } | |
478 | + | |
479 | + mem_heap_free(heap); | |
480 | + return(TRUE); | |
481 | +} | |
482 | + | |
483 | +static | |
484 | +void | |
485 | +dict_store_statistics( | |
486 | +/*==================*/ | |
487 | + dict_table_t* table) | |
488 | +{ | |
489 | + dict_index_t* index; | |
490 | + mem_heap_t* heap; | |
491 | + | |
492 | + index = dict_table_get_first_index(table); | |
493 | + | |
494 | + ut_a(index); | |
495 | + | |
496 | + heap = mem_heap_create(1000); | |
497 | + | |
498 | + while (index) { | |
499 | +/*===========================================*/ | |
500 | +{ | |
501 | + dict_table_t* sys_stats; | |
502 | + dict_index_t* sys_index; | |
503 | + btr_pcur_t pcur; | |
504 | + dtuple_t* tuple; | |
505 | + dfield_t* dfield; | |
506 | + ulint key_cols; | |
507 | + ulint n_cols; | |
508 | + ulint rests; | |
509 | + const rec_t* rec; | |
510 | + const byte* field; | |
511 | + ulint len; | |
512 | + ib_int64_t* stat_n_diff_key_vals_tmp; | |
513 | + byte* buf; | |
514 | + ulint i; | |
515 | + mtr_t mtr; | |
516 | + | |
517 | + n_cols = dict_index_get_n_unique(index); | |
518 | + stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t)); | |
519 | + | |
520 | + for (i = 0; i <= n_cols; i++) { | |
521 | + stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i]; | |
522 | + } | |
523 | + | |
524 | + sys_stats = dict_sys->sys_stats; | |
525 | + sys_index = UT_LIST_GET_FIRST(sys_stats->indexes); | |
526 | + ut_a(!dict_table_is_comp(sys_stats)); | |
527 | + | |
528 | + tuple = dtuple_create(heap, 1); | |
529 | + dfield = dtuple_get_nth_field(tuple, 0); | |
530 | + | |
531 | + buf = mem_heap_alloc(heap, 8); | |
532 | + mach_write_to_8(buf, index->id); | |
533 | + | |
534 | + dfield_set_data(dfield, buf, 8); | |
535 | + dict_index_copy_types(tuple, sys_index, 1); | |
536 | + | |
537 | + mtr_start(&mtr); | |
538 | + | |
539 | + btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, | |
540 | + BTR_MODIFY_LEAF, &pcur, &mtr); | |
541 | + rests = n_cols + 1; | |
542 | + for (i = 0; i <= n_cols; i++) { | |
543 | + rec = btr_pcur_get_rec(&pcur); | |
544 | + | |
545 | + if (!btr_pcur_is_on_user_rec(&pcur) | |
546 | + || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len)) | |
547 | + != index->id) { | |
548 | + /* not found */ | |
d8778560 AM |
549 | + |
550 | + | |
b4e1fa2c AM |
551 | + break; |
552 | + } | |
553 | + | |
554 | + if (rec_get_deleted_flag(rec, 0)) { | |
555 | + goto next_rec; | |
556 | + } | |
557 | + | |
558 | + field = rec_get_nth_field_old(rec, 1, &len); | |
559 | + ut_a(len == 4); | |
560 | + | |
561 | + key_cols = mach_read_from_4(field); | |
562 | + | |
563 | + field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len); | |
564 | + ut_a(len == 8); | |
565 | + | |
566 | + mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr); | |
567 | + | |
568 | + rests--; | |
569 | + | |
570 | +next_rec: | |
571 | + btr_pcur_move_to_next_user_rec(&pcur, &mtr); | |
572 | + } | |
573 | + btr_pcur_close(&pcur); | |
574 | + mtr_commit(&mtr); | |
575 | + | |
576 | + if (rests) { | |
577 | + fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries" | |
578 | + " of %s/%s to SYS_STATS system table.\n", | |
579 | + rests, index->table_name, index->name); | |
580 | + } | |
581 | +} | |
582 | +/*===========================================*/ | |
583 | + | |
584 | + index = dict_table_get_next_index(index); | |
585 | + } | |
586 | + | |
587 | + mem_heap_free(heap); | |
588 | +} | |
589 | + | |
590 | +/*********************************************************************//** | |
591 | Calculates new estimates for table and index statistics. The statistics | |
592 | are used in query optimization. */ | |
593 | UNIV_INTERN | |
df1b5770 | 594 | @@ -4317,10 +4551,11 @@ |
b4e1fa2c AM |
595 | dict_update_statistics( |
596 | /*===================*/ | |
597 | dict_table_t* table, /*!< in/out: table */ | |
598 | - ibool only_calc_if_missing_stats)/*!< in: only | |
599 | + ibool only_calc_if_missing_stats,/*!< in: only | |
600 | update/recalc the stats if they have | |
601 | not been initialized yet, otherwise | |
602 | do nothing */ | |
603 | + ibool sync) /*!< in: TRUE if must update SYS_STATS */ | |
604 | { | |
605 | dict_index_t* index; | |
606 | ulint sum_of_index_sizes = 0; | |
df1b5770 | 607 | @@ -4337,6 +4572,27 @@ |
b4e1fa2c AM |
608 | return; |
609 | } | |
610 | ||
611 | + if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) && !sync) { | |
612 | + dict_table_stats_lock(table, RW_X_LATCH); | |
613 | + | |
614 | + /* reload statistics from SYS_STATS table */ | |
615 | + if (dict_reload_statistics(table, &sum_of_index_sizes)) { | |
616 | + /* success */ | |
617 | +#ifdef UNIV_DEBUG | |
d8778560 | 618 | + fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n", |
b4e1fa2c AM |
619 | + table->name); |
620 | +#endif | |
621 | + goto end; | |
622 | + } | |
623 | + | |
624 | + dict_table_stats_unlock(table, RW_X_LATCH); | |
625 | + } | |
626 | +#ifdef UNIV_DEBUG | |
627 | + fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n", | |
628 | + table->name); | |
629 | +#endif | |
630 | + sum_of_index_sizes = 0; | |
631 | + | |
632 | /* Find out the sizes of the indexes and how many different values | |
633 | for the key they approximately have */ | |
634 | ||
df1b5770 | 635 | @@ -4401,6 +4657,11 @@ |
b4e1fa2c AM |
636 | index = dict_table_get_next_index(index); |
637 | } while (index); | |
638 | ||
639 | + if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY)) { | |
640 | + /* store statistics to SYS_STATS table */ | |
641 | + dict_store_statistics(table); | |
642 | + } | |
643 | +end: | |
644 | index = dict_table_get_first_index(table); | |
645 | ||
646 | table->stat_n_rows = index->stat_n_diff_key_vals[ | |
df1b5770 | 647 | @@ -4495,7 +4756,8 @@ |
b4e1fa2c AM |
648 | |
649 | ut_ad(mutex_own(&(dict_sys->mutex))); | |
650 | ||
651 | - dict_update_statistics(table, FALSE /* update even if initialized */); | |
652 | + if (srv_stats_auto_update) | |
653 | + dict_update_statistics(table, FALSE /* update even if initialized */, FALSE); | |
654 | ||
655 | dict_table_stats_lock(table, RW_S_LATCH); | |
656 | ||
657 | diff -ruN a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c | |
658 | --- a/storage/innobase/dict/dict0load.c 2010-11-03 07:01:13.000000000 +0900 | |
659 | +++ b/storage/innobase/dict/dict0load.c 2010-12-03 17:19:24.845947460 +0900 | |
d8778560 | 660 | @@ -50,7 +50,8 @@ |
b4e1fa2c AM |
661 | "SYS_COLUMNS", |
662 | "SYS_FIELDS", | |
663 | "SYS_FOREIGN", | |
664 | - "SYS_FOREIGN_COLS" | |
665 | + "SYS_FOREIGN_COLS", | |
666 | + "SYS_STATS" | |
667 | }; | |
668 | /****************************************************************//** | |
669 | Compare the name of an index column. | |
d8778560 | 670 | @@ -343,12 +344,13 @@ |
b4e1fa2c AM |
671 | } |
672 | ||
673 | if ((status & DICT_TABLE_UPDATE_STATS) | |
674 | + && srv_stats_auto_update | |
675 | && dict_table_get_first_index(*table)) { | |
676 | ||
677 | /* Update statistics if DICT_TABLE_UPDATE_STATS | |
678 | is set */ | |
679 | dict_update_statistics(*table, FALSE /* update even if | |
680 | - initialized */); | |
681 | + initialized */, FALSE); | |
682 | } | |
683 | ||
684 | return(NULL); | |
d8778560 AM |
685 | @@ -582,6 +584,61 @@ |
686 | //#endif /* FOREIGN_NOT_USED */ | |
b4e1fa2c | 687 | |
d8778560 | 688 | /********************************************************************//** |
b4e1fa2c AM |
689 | +This function parses a SYS_STATS record and extract necessary |
690 | +information from the record and return to caller. | |
691 | +@return error message, or NULL on success */ | |
692 | +UNIV_INTERN | |
693 | +const char* | |
694 | +dict_process_sys_stats_rec( | |
695 | +/*=============================*/ | |
d8778560 | 696 | + mem_heap_t* heap __attribute__((unused)), /*!< in/out: heap memory */ |
b4e1fa2c AM |
697 | + const rec_t* rec, /*!< in: current SYS_STATS rec */ |
698 | + index_id_t* index_id, /*!< out: INDEX_ID */ | |
699 | + ulint* key_cols, /*!< out: KEY_COLS */ | |
700 | + ib_uint64_t* diff_vals) /*!< out: DIFF_VALS */ | |
701 | +{ | |
702 | + ulint len; | |
703 | + const byte* field; | |
704 | + | |
705 | + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { | |
706 | + return("delete-marked record in SYS_STATS"); | |
707 | + } | |
708 | + | |
709 | + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) { | |
710 | + return("wrong number of columns in SYS_STATS record"); | |
711 | + } | |
712 | + | |
713 | + field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len); | |
714 | + if (UNIV_UNLIKELY(len != 8)) { | |
715 | +err_len: | |
716 | + return("incorrect column length in SYS_STATS"); | |
717 | + } | |
718 | + *index_id = mach_read_from_8(field); | |
719 | + | |
720 | + field = rec_get_nth_field_old(rec, 1/*KEY_COLS*/, &len); | |
721 | + if (UNIV_UNLIKELY(len != 4)) { | |
722 | + goto err_len; | |
723 | + } | |
724 | + *key_cols = mach_read_from_4(field); | |
725 | + | |
726 | + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len); | |
727 | + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { | |
728 | + goto err_len; | |
729 | + } | |
730 | + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len); | |
731 | + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { | |
732 | + goto err_len; | |
733 | + } | |
734 | + | |
735 | + field = rec_get_nth_field_old(rec, 4/*DIFF_VALS*/, &len); | |
736 | + if (UNIV_UNLIKELY(len != 8)) { | |
737 | + goto err_len; | |
738 | + } | |
739 | + *diff_vals = mach_read_from_8(field); | |
740 | + | |
741 | + return(NULL); | |
742 | +} | |
d8778560 | 743 | +/********************************************************************//** |
b4e1fa2c AM |
744 | Determine the flags of a table described in SYS_TABLES. |
745 | @return compressed page size in kilobytes; or 0 if the tablespace is | |
d8778560 | 746 | uncompressed, ULINT_UNDEFINED on error */ |
b4e1fa2c AM |
747 | diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc |
748 | --- a/storage/innobase/handler/ha_innodb.cc 2010-12-03 17:17:03.665960357 +0900 | |
749 | +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-03 17:22:21.586939783 +0900 | |
750 | @@ -187,6 +187,7 @@ | |
751 | static my_bool innobase_rollback_on_timeout = FALSE; | |
752 | static my_bool innobase_create_status_file = FALSE; | |
753 | static my_bool innobase_stats_on_metadata = TRUE; | |
754 | +static my_bool innobase_use_sys_stats_table = FALSE; | |
755 | ||
756 | ||
757 | static char* internal_innobase_data_file_path = NULL; | |
df1b5770 | 758 | @@ -2407,6 +2408,8 @@ |
b4e1fa2c AM |
759 | goto error; |
760 | } | |
761 | ||
762 | + srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table; | |
763 | + | |
764 | /* -------------- Log files ---------------------------*/ | |
765 | ||
766 | /* The default dir for log files is the datadir of MySQL */ | |
df1b5770 | 767 | @@ -5211,6 +5214,10 @@ |
b4e1fa2c AM |
768 | |
769 | error = row_insert_for_mysql((byte*) record, prebuilt); | |
770 | ||
771 | +#ifdef EXTENDED_FOR_USERSTAT | |
772 | + if (error == DB_SUCCESS) rows_changed++; | |
773 | +#endif | |
774 | + | |
775 | /* Handle duplicate key errors */ | |
776 | if (auto_inc_used) { | |
777 | ulint err; | |
df1b5770 | 778 | @@ -5547,6 +5554,10 @@ |
b4e1fa2c AM |
779 | } |
780 | } | |
781 | ||
782 | +#ifdef EXTENDED_FOR_USERSTAT | |
783 | + if (error == DB_SUCCESS) rows_changed++; | |
784 | +#endif | |
785 | + | |
786 | innodb_srv_conc_exit_innodb(trx); | |
787 | ||
788 | error = convert_error_code_to_mysql(error, | |
df1b5770 | 789 | @@ -5600,6 +5611,10 @@ |
b4e1fa2c AM |
790 | |
791 | error = row_update_for_mysql((byte*) record, prebuilt); | |
792 | ||
793 | +#ifdef EXTENDED_FOR_USERSTAT | |
794 | + if (error == DB_SUCCESS) rows_changed++; | |
795 | +#endif | |
796 | + | |
797 | innodb_srv_conc_exit_innodb(trx); | |
798 | ||
799 | error = convert_error_code_to_mysql( | |
df1b5770 | 800 | @@ -5918,6 +5933,11 @@ |
d8778560 AM |
801 | case DB_SUCCESS: |
802 | error = 0; | |
803 | table->status = 0; | |
804 | +#ifdef EXTENDED_FOR_USERSTAT | |
805 | + rows_read++; | |
806 | + if (active_index >= 0 && active_index < MAX_KEY) | |
807 | + index_rows_read[active_index]++; | |
808 | +#endif | |
809 | break; | |
810 | case DB_RECORD_NOT_FOUND: | |
811 | error = HA_ERR_KEY_NOT_FOUND; | |
df1b5770 | 812 | @@ -6127,6 +6147,11 @@ |
b4e1fa2c AM |
813 | case DB_SUCCESS: |
814 | error = 0; | |
815 | table->status = 0; | |
816 | +#ifdef EXTENDED_FOR_USERSTAT | |
817 | + rows_read++; | |
818 | + if (active_index >= 0 && active_index < MAX_KEY) | |
819 | + index_rows_read[active_index]++; | |
820 | +#endif | |
821 | break; | |
822 | case DB_RECORD_NOT_FOUND: | |
823 | error = HA_ERR_END_OF_FILE; | |
df1b5770 | 824 | @@ -8077,11 +8102,31 @@ |
b4e1fa2c AM |
825 | /* In sql_show we call with this flag: update |
826 | then statistics so that they are up-to-date */ | |
827 | ||
828 | + if (srv_use_sys_stats_table && !((ib_table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) | |
829 | + && called_from_analyze) { | |
830 | + /* If the indexes on the table don't have enough rows in SYS_STATS system table, */ | |
831 | + /* they need to be created. */ | |
832 | + dict_index_t* index; | |
833 | + | |
834 | + prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics"; | |
835 | + | |
836 | + ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED); | |
837 | + | |
838 | + for (index = dict_table_get_first_index(ib_table); | |
839 | + index != NULL; | |
840 | + index = dict_table_get_next_index(index)) { | |
841 | + row_insert_stats_for_mysql(index, prebuilt->trx); | |
842 | + innobase_commit_low(prebuilt->trx); | |
843 | + } | |
844 | + | |
845 | + ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED); | |
846 | + } | |
847 | + | |
848 | prebuilt->trx->op_info = "updating table statistics"; | |
849 | ||
850 | dict_update_statistics(ib_table, | |
851 | FALSE /* update even if stats | |
852 | - are initialized */); | |
853 | + are initialized */, called_from_analyze); | |
854 | ||
855 | prebuilt->trx->op_info = "returning various info to MySQL"; | |
856 | } | |
df1b5770 | 857 | @@ -8159,7 +8204,7 @@ |
b4e1fa2c AM |
858 | are asked by MySQL to avoid locking. Another reason to |
859 | avoid the call is that it uses quite a lot of CPU. | |
860 | See Bug#38185. */ | |
d8778560 AM |
861 | - if (flag & HA_STATUS_NO_LOCK |
862 | + if (flag & HA_STATUS_NO_LOCK || !srv_stats_update_need_lock | |
863 | || !(flag & HA_STATUS_VARIABLE_EXTRA)) { | |
b4e1fa2c AM |
864 | /* We do not update delete_length if no |
865 | locking is requested so the "old" value can | |
df1b5770 | 866 | @@ -11354,6 +11399,26 @@ |
b4e1fa2c AM |
867 | "The number of index pages to sample when calculating statistics (default 8)", |
868 | NULL, NULL, 8, 1, ~0ULL, 0); | |
869 | ||
b4e1fa2c AM |
870 | +static MYSQL_SYSVAR_ULONG(stats_auto_update, srv_stats_auto_update, |
871 | + PLUGIN_VAR_RQCMDARG, | |
872 | + "Enable/Disable InnoDB's auto update statistics of indexes. " | |
873 | + "(except for ANALYZE TABLE command) 0:disable 1:enable", | |
874 | + NULL, NULL, 1, 0, 1, 0); | |
875 | + | |
876 | +static MYSQL_SYSVAR_ULONG(stats_update_need_lock, srv_stats_update_need_lock, | |
877 | + PLUGIN_VAR_RQCMDARG, | |
878 | + "Enable/Disable InnoDB's update statistics which needs to lock dictionary. " | |
879 | + "e.g. Data_free.", | |
880 | + NULL, NULL, 1, 0, 1, 0); | |
881 | + | |
882 | +static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table, | |
883 | + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, | |
884 | + "Enable to use SYS_STATS system table to store statistics statically, " | |
885 | + "And avoids to calculate statistics at every first open of the tables. " | |
886 | + "This option may make the opportunities of update statistics less. " | |
887 | + "So you should use ANALYZE TABLE command intentionally.", | |
888 | + NULL, NULL, FALSE); | |
889 | + | |
890 | static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled, | |
891 | PLUGIN_VAR_OPCMDARG, | |
892 | "Enable InnoDB adaptive hash index (enabled by default). " | |
df1b5770 | 893 | @@ -11684,6 +11749,9 @@ |
a9ee80b9 | 894 | MYSQL_SYSVAR(recovery_update_relay_log), |
b4e1fa2c AM |
895 | MYSQL_SYSVAR(rollback_on_timeout), |
896 | MYSQL_SYSVAR(stats_on_metadata), | |
b4e1fa2c AM |
897 | + MYSQL_SYSVAR(stats_auto_update), |
898 | + MYSQL_SYSVAR(stats_update_need_lock), | |
899 | + MYSQL_SYSVAR(use_sys_stats_table), | |
900 | MYSQL_SYSVAR(stats_sample_pages), | |
901 | MYSQL_SYSVAR(adaptive_hash_index), | |
df1b5770 AM |
902 | MYSQL_SYSVAR(stats_method), |
903 | @@ -11753,7 +11821,10 @@ | |
b4e1fa2c AM |
904 | i_s_innodb_sys_columns, |
905 | i_s_innodb_sys_fields, | |
906 | i_s_innodb_sys_foreign, | |
907 | -i_s_innodb_sys_foreign_cols | |
908 | +i_s_innodb_sys_foreign_cols, | |
909 | +i_s_innodb_sys_stats, | |
910 | +i_s_innodb_table_stats, | |
911 | +i_s_innodb_index_stats | |
912 | mysql_declare_plugin_end; | |
913 | ||
914 | /** @brief Initialize the default value of innodb_commit_concurrency. | |
915 | diff -ruN a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc | |
916 | --- a/storage/innobase/handler/i_s.cc 2010-12-03 17:17:03.666956117 +0900 | |
917 | +++ b/storage/innobase/handler/i_s.cc 2010-12-03 17:19:24.880964526 +0900 | |
918 | @@ -49,6 +49,7 @@ | |
919 | #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ | |
920 | #include "trx0rseg.h" /* for trx_rseg_struct */ | |
921 | #include "trx0sys.h" /* for trx_sys */ | |
922 | +#include "dict0dict.h" /* for dict_sys */ | |
923 | } | |
924 | ||
925 | static const char plugin_author[] = "Innobase Oy"; | |
d8778560 | 926 | @@ -3457,6 +3458,203 @@ |
b4e1fa2c AM |
927 | STRUCT_FLD(__reserved1, NULL) |
928 | }; | |
929 | ||
930 | +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_stats */ | |
931 | +static ST_FIELD_INFO innodb_sys_stats_fields_info[] = | |
932 | +{ | |
933 | +#define SYS_STATS_INDEX_ID 0 | |
934 | + {STRUCT_FLD(field_name, "INDEX_ID"), | |
935 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
936 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
937 | + STRUCT_FLD(value, 0), | |
938 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
939 | + STRUCT_FLD(old_name, ""), | |
940 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
941 | + | |
942 | +#define SYS_STATS_KEY_COLS 1 | |
943 | + {STRUCT_FLD(field_name, "KEY_COLS"), | |
944 | + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), | |
945 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), | |
946 | + STRUCT_FLD(value, 0), | |
947 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
948 | + STRUCT_FLD(old_name, ""), | |
949 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
950 | + | |
951 | +#define SYS_STATS_DIFF_VALS 2 | |
952 | + {STRUCT_FLD(field_name, "DIFF_VALS"), | |
953 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
954 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
955 | + STRUCT_FLD(value, 0), | |
956 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
957 | + STRUCT_FLD(old_name, ""), | |
958 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
959 | + | |
960 | + END_OF_ST_FIELD_INFO | |
961 | +}; | |
962 | +/**********************************************************************//** | |
963 | +Function to fill information_schema.innodb_sys_stats | |
964 | +@return 0 on success */ | |
965 | +static | |
966 | +int | |
967 | +i_s_dict_fill_sys_stats( | |
968 | +/*====================*/ | |
969 | + THD* thd, /*!< in: thread */ | |
970 | + index_id_t index_id, /*!< in: INDEX_ID */ | |
971 | + ulint key_cols, /*!< in: KEY_COLS */ | |
972 | + ib_uint64_t diff_vals, /*!< in: DIFF_VALS */ | |
973 | + TABLE* table_to_fill) /*!< in/out: fill this table */ | |
974 | +{ | |
975 | + Field** fields; | |
976 | + | |
977 | + DBUG_ENTER("i_s_dict_fill_sys_stats"); | |
978 | + | |
979 | + fields = table_to_fill->field; | |
980 | + | |
981 | + OK(fields[SYS_STATS_INDEX_ID]->store(longlong(index_id), TRUE)); | |
982 | + | |
983 | + OK(fields[SYS_STATS_KEY_COLS]->store(key_cols)); | |
984 | + | |
985 | + OK(fields[SYS_STATS_DIFF_VALS]->store(longlong(diff_vals), TRUE)); | |
986 | + | |
987 | + OK(schema_table_store_record(thd, table_to_fill)); | |
988 | + | |
989 | + DBUG_RETURN(0); | |
990 | +} | |
991 | +/*******************************************************************//** | |
992 | +Function to populate INFORMATION_SCHEMA.innodb_sys_stats table. | |
993 | +@return 0 on success */ | |
994 | +static | |
995 | +int | |
996 | +i_s_sys_stats_fill_table( | |
997 | +/*=====================*/ | |
998 | + THD* thd, /*!< in: thread */ | |
999 | + TABLE_LIST* tables, /*!< in/out: tables to fill */ | |
1000 | + COND* cond) /*!< in: condition (not used) */ | |
1001 | +{ | |
1002 | + btr_pcur_t pcur; | |
1003 | + const rec_t* rec; | |
1004 | + mem_heap_t* heap; | |
1005 | + mtr_t mtr; | |
1006 | + | |
1007 | + DBUG_ENTER("i_s_sys_stats_fill_table"); | |
1008 | + | |
1009 | + /* deny access to non-superusers */ | |
1010 | + if (check_global_access(thd, PROCESS_ACL)) { | |
1011 | + DBUG_RETURN(0); | |
1012 | + } | |
1013 | + | |
1014 | + heap = mem_heap_create(1000); | |
1015 | + mutex_enter(&dict_sys->mutex); | |
1016 | + mtr_start(&mtr); | |
1017 | + | |
1018 | + rec = dict_startscan_system(&pcur, &mtr, SYS_STATS); | |
1019 | + | |
1020 | + while (rec) { | |
1021 | + const char* err_msg; | |
1022 | + index_id_t index_id; | |
1023 | + ulint key_cols; | |
1024 | + ib_uint64_t diff_vals; | |
1025 | + | |
1026 | + /* Extract necessary information from a SYS_FOREIGN_COLS row */ | |
1027 | + err_msg = dict_process_sys_stats_rec( | |
1028 | + heap, rec, &index_id, &key_cols, &diff_vals); | |
1029 | + | |
1030 | + mtr_commit(&mtr); | |
1031 | + mutex_exit(&dict_sys->mutex); | |
1032 | + | |
1033 | + if (!err_msg) { | |
1034 | + i_s_dict_fill_sys_stats( | |
1035 | + thd, index_id, key_cols, diff_vals, | |
1036 | + tables->table); | |
1037 | + } else { | |
1038 | + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, | |
1039 | + ER_CANT_FIND_SYSTEM_REC, | |
1040 | + err_msg); | |
1041 | + } | |
1042 | + | |
1043 | + mem_heap_empty(heap); | |
1044 | + | |
1045 | + /* Get the next record */ | |
1046 | + mutex_enter(&dict_sys->mutex); | |
1047 | + mtr_start(&mtr); | |
1048 | + rec = dict_getnext_system(&pcur, &mtr); | |
1049 | + } | |
1050 | + | |
1051 | + mtr_commit(&mtr); | |
1052 | + mutex_exit(&dict_sys->mutex); | |
1053 | + mem_heap_free(heap); | |
1054 | + | |
1055 | + DBUG_RETURN(0); | |
1056 | +} | |
1057 | +/*******************************************************************//** | |
1058 | +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_stats | |
1059 | +@return 0 on success */ | |
1060 | +static | |
1061 | +int | |
1062 | +innodb_sys_stats_init( | |
1063 | +/*========================*/ | |
1064 | + void* p) /*!< in/out: table schema object */ | |
1065 | +{ | |
1066 | + ST_SCHEMA_TABLE* schema; | |
1067 | + | |
1068 | + DBUG_ENTER("innodb_sys_stats_init"); | |
1069 | + | |
1070 | + schema = (ST_SCHEMA_TABLE*) p; | |
1071 | + | |
1072 | + schema->fields_info = innodb_sys_stats_fields_info; | |
1073 | + schema->fill_table = i_s_sys_stats_fill_table; | |
1074 | + | |
1075 | + DBUG_RETURN(0); | |
1076 | +} | |
1077 | + | |
1078 | +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_stats = | |
1079 | +{ | |
1080 | + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ | |
1081 | + /* int */ | |
1082 | + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), | |
1083 | + | |
1084 | + /* pointer to type-specific plugin descriptor */ | |
1085 | + /* void* */ | |
1086 | + STRUCT_FLD(info, &i_s_info), | |
1087 | + | |
1088 | + /* plugin name */ | |
1089 | + /* const char* */ | |
1090 | + STRUCT_FLD(name, "INNODB_SYS_STATS"), | |
1091 | + | |
1092 | + /* plugin author (for SHOW PLUGINS) */ | |
1093 | + /* const char* */ | |
1094 | + STRUCT_FLD(author, plugin_author), | |
1095 | + | |
1096 | + /* general descriptive text (for SHOW PLUGINS) */ | |
1097 | + /* const char* */ | |
1098 | + STRUCT_FLD(descr, "XtraDB SYS_STATS table"), | |
1099 | + | |
1100 | + /* the plugin license (PLUGIN_LICENSE_XXX) */ | |
1101 | + /* int */ | |
1102 | + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), | |
1103 | + | |
1104 | + /* the function to invoke when plugin is loaded */ | |
1105 | + /* int (*)(void*); */ | |
1106 | + STRUCT_FLD(init, innodb_sys_stats_init), | |
1107 | + | |
1108 | + /* the function to invoke when plugin is unloaded */ | |
1109 | + /* int (*)(void*); */ | |
1110 | + STRUCT_FLD(deinit, i_s_common_deinit), | |
1111 | + | |
1112 | + /* plugin version (for SHOW PLUGINS) */ | |
1113 | + /* unsigned int */ | |
1114 | + STRUCT_FLD(version, INNODB_VERSION_SHORT), | |
1115 | + | |
1116 | + /* struct st_mysql_show_var* */ | |
1117 | + STRUCT_FLD(status_vars, NULL), | |
1118 | + | |
1119 | + /* struct st_mysql_sys_var** */ | |
1120 | + STRUCT_FLD(system_vars, NULL), | |
1121 | + | |
1122 | + /* reserved for dependency checking */ | |
1123 | + /* void* */ | |
1124 | + STRUCT_FLD(__reserved1, NULL) | |
1125 | +}; | |
1126 | + | |
1127 | /*********************************************************************** | |
1128 | */ | |
1129 | static ST_FIELD_INFO i_s_innodb_rseg_fields_info[] = | |
d8778560 | 1130 | @@ -3619,3 +3817,347 @@ |
b4e1fa2c AM |
1131 | /* void* */ |
1132 | STRUCT_FLD(__reserved1, NULL) | |
1133 | }; | |
1134 | + | |
1135 | +/*********************************************************************** | |
1136 | +*/ | |
1137 | +static ST_FIELD_INFO i_s_innodb_table_stats_info[] = | |
1138 | +{ | |
1139 | + {STRUCT_FLD(field_name, "table_schema"), | |
1140 | + STRUCT_FLD(field_length, NAME_LEN), | |
1141 | + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), | |
1142 | + STRUCT_FLD(value, 0), | |
1143 | + STRUCT_FLD(field_flags, 0), | |
1144 | + STRUCT_FLD(old_name, ""), | |
1145 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1146 | + | |
1147 | + {STRUCT_FLD(field_name, "table_name"), | |
1148 | + STRUCT_FLD(field_length, NAME_LEN), | |
1149 | + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), | |
1150 | + STRUCT_FLD(value, 0), | |
1151 | + STRUCT_FLD(field_flags, 0), | |
1152 | + STRUCT_FLD(old_name, ""), | |
1153 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1154 | + | |
1155 | + {STRUCT_FLD(field_name, "rows"), | |
1156 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1157 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1158 | + STRUCT_FLD(value, 0), | |
1159 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1160 | + STRUCT_FLD(old_name, ""), | |
1161 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1162 | + | |
1163 | + {STRUCT_FLD(field_name, "clust_size"), | |
1164 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1165 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1166 | + STRUCT_FLD(value, 0), | |
1167 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1168 | + STRUCT_FLD(old_name, ""), | |
1169 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1170 | + | |
1171 | + {STRUCT_FLD(field_name, "other_size"), | |
1172 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1173 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1174 | + STRUCT_FLD(value, 0), | |
1175 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1176 | + STRUCT_FLD(old_name, ""), | |
1177 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1178 | + | |
1179 | + {STRUCT_FLD(field_name, "modified"), | |
1180 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1181 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1182 | + STRUCT_FLD(value, 0), | |
1183 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1184 | + STRUCT_FLD(old_name, ""), | |
1185 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1186 | + | |
1187 | + END_OF_ST_FIELD_INFO | |
1188 | +}; | |
1189 | + | |
1190 | +static ST_FIELD_INFO i_s_innodb_index_stats_info[] = | |
1191 | +{ | |
1192 | + {STRUCT_FLD(field_name, "table_schema"), | |
1193 | + STRUCT_FLD(field_length, NAME_LEN), | |
1194 | + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), | |
1195 | + STRUCT_FLD(value, 0), | |
1196 | + STRUCT_FLD(field_flags, 0), | |
1197 | + STRUCT_FLD(old_name, ""), | |
1198 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1199 | + | |
1200 | + {STRUCT_FLD(field_name, "table_name"), | |
1201 | + STRUCT_FLD(field_length, NAME_LEN), | |
1202 | + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), | |
1203 | + STRUCT_FLD(value, 0), | |
1204 | + STRUCT_FLD(field_flags, 0), | |
1205 | + STRUCT_FLD(old_name, ""), | |
1206 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1207 | + | |
1208 | + {STRUCT_FLD(field_name, "index_name"), | |
1209 | + STRUCT_FLD(field_length, NAME_LEN), | |
1210 | + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), | |
1211 | + STRUCT_FLD(value, 0), | |
1212 | + STRUCT_FLD(field_flags, 0), | |
1213 | + STRUCT_FLD(old_name, ""), | |
1214 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1215 | + | |
1216 | + {STRUCT_FLD(field_name, "fields"), | |
1217 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1218 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1219 | + STRUCT_FLD(value, 0), | |
1220 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1221 | + STRUCT_FLD(old_name, ""), | |
1222 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1223 | + | |
1224 | + {STRUCT_FLD(field_name, "rows_per_key"), | |
1225 | + STRUCT_FLD(field_length, 256), | |
1226 | + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), | |
1227 | + STRUCT_FLD(value, 0), | |
1228 | + STRUCT_FLD(field_flags, 0), | |
1229 | + STRUCT_FLD(old_name, ""), | |
1230 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1231 | + | |
1232 | + {STRUCT_FLD(field_name, "index_total_pages"), | |
1233 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1234 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1235 | + STRUCT_FLD(value, 0), | |
1236 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1237 | + STRUCT_FLD(old_name, ""), | |
1238 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1239 | + | |
1240 | + {STRUCT_FLD(field_name, "index_leaf_pages"), | |
1241 | + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), | |
1242 | + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), | |
1243 | + STRUCT_FLD(value, 0), | |
1244 | + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), | |
1245 | + STRUCT_FLD(old_name, ""), | |
1246 | + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, | |
1247 | + | |
1248 | + END_OF_ST_FIELD_INFO | |
1249 | +}; | |
1250 | + | |
1251 | +static | |
1252 | +int | |
1253 | +i_s_innodb_table_stats_fill( | |
1254 | +/*========================*/ | |
1255 | + THD* thd, | |
1256 | + TABLE_LIST* tables, | |
1257 | + COND* cond) | |
1258 | +{ | |
1259 | + TABLE* i_s_table = (TABLE *) tables->table; | |
1260 | + int status = 0; | |
1261 | + dict_table_t* table; | |
1262 | + | |
1263 | + DBUG_ENTER("i_s_innodb_table_stats_fill"); | |
1264 | + | |
1265 | + /* deny access to non-superusers */ | |
1266 | + if (check_global_access(thd, PROCESS_ACL)) { | |
1267 | + DBUG_RETURN(0); | |
1268 | + } | |
1269 | + | |
1270 | + mutex_enter(&(dict_sys->mutex)); | |
1271 | + | |
1272 | + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); | |
1273 | + | |
1274 | + while (table) { | |
1275 | + char buf[NAME_LEN * 2 + 2]; | |
1276 | + char* ptr; | |
1277 | + | |
1278 | + if (table->stat_clustered_index_size == 0) { | |
1279 | + table = UT_LIST_GET_NEXT(table_LRU, table); | |
1280 | + continue; | |
1281 | + } | |
1282 | + | |
1283 | + buf[NAME_LEN * 2 + 1] = 0; | |
1284 | + strncpy(buf, table->name, NAME_LEN * 2 + 1); | |
1285 | + ptr = strchr(buf, '/'); | |
1286 | + if (ptr) { | |
1287 | + *ptr = '\0'; | |
1288 | + ++ptr; | |
1289 | + } else { | |
1290 | + ptr = buf; | |
1291 | + } | |
1292 | + | |
1293 | + field_store_string(i_s_table->field[0], buf); | |
1294 | + field_store_string(i_s_table->field[1], ptr); | |
1295 | + i_s_table->field[2]->store(table->stat_n_rows); | |
1296 | + i_s_table->field[3]->store(table->stat_clustered_index_size); | |
1297 | + i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes); | |
1298 | + i_s_table->field[5]->store(table->stat_modified_counter); | |
1299 | + | |
1300 | + if (schema_table_store_record(thd, i_s_table)) { | |
1301 | + status = 1; | |
1302 | + break; | |
1303 | + } | |
1304 | + | |
1305 | + table = UT_LIST_GET_NEXT(table_LRU, table); | |
1306 | + } | |
1307 | + | |
1308 | + mutex_exit(&(dict_sys->mutex)); | |
1309 | + | |
1310 | + DBUG_RETURN(status); | |
1311 | +} | |
1312 | + | |
1313 | +static | |
1314 | +int | |
1315 | +i_s_innodb_index_stats_fill( | |
1316 | +/*========================*/ | |
1317 | + THD* thd, | |
1318 | + TABLE_LIST* tables, | |
1319 | + COND* cond) | |
1320 | +{ | |
1321 | + TABLE* i_s_table = (TABLE *) tables->table; | |
1322 | + int status = 0; | |
1323 | + dict_table_t* table; | |
1324 | + dict_index_t* index; | |
1325 | + | |
1326 | + DBUG_ENTER("i_s_innodb_index_stats_fill"); | |
1327 | + | |
1328 | + /* deny access to non-superusers */ | |
1329 | + if (check_global_access(thd, PROCESS_ACL)) { | |
1330 | + DBUG_RETURN(0); | |
1331 | + } | |
1332 | + | |
1333 | + mutex_enter(&(dict_sys->mutex)); | |
1334 | + | |
1335 | + table = UT_LIST_GET_FIRST(dict_sys->table_LRU); | |
1336 | + | |
1337 | + while (table) { | |
1338 | + if (table->stat_clustered_index_size == 0) { | |
1339 | + table = UT_LIST_GET_NEXT(table_LRU, table); | |
1340 | + continue; | |
1341 | + } | |
1342 | + | |
1343 | + ib_int64_t n_rows = table->stat_n_rows; | |
1344 | + | |
1345 | + if (n_rows < 0) { | |
1346 | + n_rows = 0; | |
1347 | + } | |
1348 | + | |
1349 | + index = dict_table_get_first_index(table); | |
1350 | + | |
1351 | + while (index) { | |
1352 | + char buff[256+1]; | |
1353 | + char row_per_keys[256+1]; | |
1354 | + char buf[NAME_LEN * 2 + 2]; | |
1355 | + char* ptr; | |
1356 | + ulint i; | |
1357 | + | |
1358 | + buf[NAME_LEN * 2 + 1] = 0; | |
1359 | + strncpy(buf, table->name, NAME_LEN * 2 + 1); | |
1360 | + ptr = strchr(buf, '/'); | |
1361 | + if (ptr) { | |
1362 | + *ptr = '\0'; | |
1363 | + ++ptr; | |
1364 | + } else { | |
1365 | + ptr = buf; | |
1366 | + } | |
1367 | + | |
1368 | + field_store_string(i_s_table->field[0], buf); | |
1369 | + field_store_string(i_s_table->field[1], ptr); | |
1370 | + field_store_string(i_s_table->field[2], index->name); | |
1371 | + i_s_table->field[3]->store(index->n_uniq); | |
1372 | + | |
1373 | + row_per_keys[0] = '\0'; | |
1374 | + | |
1375 | + /* It is remained optimistic operation still for now */ | |
1376 | + //dict_index_stat_mutex_enter(index); | |
1377 | + if (index->stat_n_diff_key_vals) { | |
1378 | + for (i = 1; i <= index->n_uniq; i++) { | |
1379 | + ib_int64_t rec_per_key; | |
1380 | + if (index->stat_n_diff_key_vals[i]) { | |
1381 | + rec_per_key = n_rows / index->stat_n_diff_key_vals[i]; | |
1382 | + } else { | |
1383 | + rec_per_key = n_rows; | |
1384 | + } | |
1385 | + ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ", | |
1386 | + rec_per_key); | |
1387 | + strncat(row_per_keys, buff, 256 - strlen(row_per_keys)); | |
1388 | + } | |
1389 | + } | |
1390 | + //dict_index_stat_mutex_exit(index); | |
1391 | + | |
1392 | + field_store_string(i_s_table->field[4], row_per_keys); | |
1393 | + | |
1394 | + i_s_table->field[5]->store(index->stat_index_size); | |
1395 | + i_s_table->field[6]->store(index->stat_n_leaf_pages); | |
1396 | + | |
1397 | + if (schema_table_store_record(thd, i_s_table)) { | |
1398 | + status = 1; | |
1399 | + break; | |
1400 | + } | |
1401 | + | |
1402 | + index = dict_table_get_next_index(index); | |
1403 | + } | |
1404 | + | |
1405 | + if (status == 1) { | |
1406 | + break; | |
1407 | + } | |
1408 | + | |
1409 | + table = UT_LIST_GET_NEXT(table_LRU, table); | |
1410 | + } | |
1411 | + | |
1412 | + mutex_exit(&(dict_sys->mutex)); | |
1413 | + | |
1414 | + DBUG_RETURN(status); | |
1415 | +} | |
1416 | + | |
1417 | +static | |
1418 | +int | |
1419 | +i_s_innodb_table_stats_init( | |
1420 | +/*========================*/ | |
1421 | + void* p) | |
1422 | +{ | |
1423 | + DBUG_ENTER("i_s_innodb_table_stats_init"); | |
1424 | + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p; | |
1425 | + | |
1426 | + schema->fields_info = i_s_innodb_table_stats_info; | |
1427 | + schema->fill_table = i_s_innodb_table_stats_fill; | |
1428 | + | |
1429 | + DBUG_RETURN(0); | |
1430 | +} | |
1431 | + | |
1432 | +static | |
1433 | +int | |
1434 | +i_s_innodb_index_stats_init( | |
1435 | +/*========================*/ | |
1436 | + void* p) | |
1437 | +{ | |
1438 | + DBUG_ENTER("i_s_innodb_index_stats_init"); | |
1439 | + ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p; | |
1440 | + | |
1441 | + schema->fields_info = i_s_innodb_index_stats_info; | |
1442 | + schema->fill_table = i_s_innodb_index_stats_fill; | |
1443 | + | |
1444 | + DBUG_RETURN(0); | |
1445 | +} | |
1446 | + | |
1447 | +UNIV_INTERN struct st_mysql_plugin i_s_innodb_table_stats = | |
1448 | +{ | |
1449 | + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), | |
1450 | + STRUCT_FLD(info, &i_s_info), | |
1451 | + STRUCT_FLD(name, "INNODB_TABLE_STATS"), | |
1452 | + STRUCT_FLD(author, plugin_author), | |
1453 | + STRUCT_FLD(descr, "InnoDB table statistics in memory"), | |
1454 | + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), | |
1455 | + STRUCT_FLD(init, i_s_innodb_table_stats_init), | |
1456 | + STRUCT_FLD(deinit, i_s_common_deinit), | |
1457 | + STRUCT_FLD(version, 0x0100 /* 1.0 */), | |
1458 | + STRUCT_FLD(status_vars, NULL), | |
1459 | + STRUCT_FLD(system_vars, NULL), | |
1460 | + STRUCT_FLD(__reserved1, NULL) | |
1461 | +}; | |
1462 | + | |
1463 | +UNIV_INTERN struct st_mysql_plugin i_s_innodb_index_stats = | |
1464 | +{ | |
1465 | + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), | |
1466 | + STRUCT_FLD(info, &i_s_info), | |
1467 | + STRUCT_FLD(name, "INNODB_INDEX_STATS"), | |
1468 | + STRUCT_FLD(author, plugin_author), | |
1469 | + STRUCT_FLD(descr, "InnoDB index statistics in memory"), | |
1470 | + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), | |
1471 | + STRUCT_FLD(init, i_s_innodb_index_stats_init), | |
1472 | + STRUCT_FLD(deinit, i_s_common_deinit), | |
1473 | + STRUCT_FLD(version, 0x0100 /* 1.0 */), | |
1474 | + STRUCT_FLD(status_vars, NULL), | |
1475 | + STRUCT_FLD(system_vars, NULL), | |
1476 | + STRUCT_FLD(__reserved1, NULL) | |
1477 | +}; | |
1478 | diff -ruN a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h | |
1479 | --- a/storage/innobase/handler/i_s.h 2010-12-03 17:17:03.668953884 +0900 | |
1480 | +++ b/storage/innobase/handler/i_s.h 2010-12-03 17:19:24.882947826 +0900 | |
1481 | @@ -41,5 +41,8 @@ | |
1482 | extern struct st_mysql_plugin i_s_innodb_sys_foreign; | |
1483 | extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols; | |
1484 | extern struct st_mysql_plugin i_s_innodb_rseg; | |
1485 | +extern struct st_mysql_plugin i_s_innodb_sys_stats; | |
1486 | +extern struct st_mysql_plugin i_s_innodb_table_stats; | |
1487 | +extern struct st_mysql_plugin i_s_innodb_index_stats; | |
1488 | ||
1489 | #endif /* i_s_h */ | |
1490 | diff -ruN a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h | |
1491 | --- a/storage/innobase/include/dict0boot.h 2010-11-03 07:01:13.000000000 +0900 | |
1492 | +++ b/storage/innobase/include/dict0boot.h 2010-12-03 17:19:24.885947372 +0900 | |
1493 | @@ -104,6 +104,7 @@ | |
1494 | #define DICT_COLUMNS_ID 2 | |
1495 | #define DICT_INDEXES_ID 3 | |
1496 | #define DICT_FIELDS_ID 4 | |
1497 | +#define DICT_STATS_ID 6 | |
1498 | /* The following is a secondary index on SYS_TABLES */ | |
1499 | #define DICT_TABLE_IDS_ID 5 | |
1500 | ||
1501 | @@ -131,10 +132,13 @@ | |
1502 | #define DICT_HDR_INDEXES 44 /* Root of the index index tree */ | |
1503 | #define DICT_HDR_FIELDS 48 /* Root of the index field | |
1504 | index tree */ | |
1505 | +#define DICT_HDR_STATS 52 /* Root of the stats tree */ | |
1506 | ||
1507 | #define DICT_HDR_FSEG_HEADER 56 /* Segment header for the tablespace | |
1508 | segment into which the dictionary | |
1509 | header is created */ | |
1510 | + | |
1511 | +#define DICT_HDR_XTRADB_MARK 256 /* Flag to distinguish expansion of XtraDB */ | |
1512 | /*-------------------------------------------------------------*/ | |
1513 | ||
1514 | /* The field number of the page number field in the sys_indexes table | |
1515 | @@ -144,11 +148,15 @@ | |
1516 | #define DICT_SYS_INDEXES_TYPE_FIELD 6 | |
1517 | #define DICT_SYS_INDEXES_NAME_FIELD 4 | |
1518 | ||
1519 | +#define DICT_SYS_STATS_DIFF_VALS_FIELD 4 | |
1520 | + | |
1521 | /* When a row id which is zero modulo this number (which must be a power of | |
1522 | two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is | |
1523 | updated */ | |
1524 | #define DICT_HDR_ROW_ID_WRITE_MARGIN 256 | |
1525 | ||
1526 | +#define DICT_HDR_XTRADB_FLAG 0x5854524144425F31ULL /* "XTRADB_1" */ | |
1527 | + | |
1528 | #ifndef UNIV_NONINL | |
1529 | #include "dict0boot.ic" | |
1530 | #endif | |
1531 | diff -ruN a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h | |
1532 | --- a/storage/innobase/include/dict0crea.h 2010-11-03 07:01:13.000000000 +0900 | |
1533 | +++ b/storage/innobase/include/dict0crea.h 2010-12-03 17:19:24.886949643 +0900 | |
1534 | @@ -53,6 +53,14 @@ | |
1535 | dict_index_t* index, /*!< in: index to create, built as a memory data | |
1536 | structure */ | |
1537 | mem_heap_t* heap); /*!< in: heap where created */ | |
1538 | +/*********************************************************************//** | |
1539 | +*/ | |
1540 | +UNIV_INTERN | |
1541 | +ind_node_t* | |
1542 | +ind_insert_stats_graph_create( | |
1543 | +/*==========================*/ | |
1544 | + dict_index_t* index, | |
1545 | + mem_heap_t* heap); | |
1546 | /***********************************************************//** | |
1547 | Creates a table. This is a high-level function used in SQL execution graphs. | |
1548 | @return query thread to run next or NULL */ | |
1549 | @@ -62,6 +70,13 @@ | |
1550 | /*===================*/ | |
1551 | que_thr_t* thr); /*!< in: query thread */ | |
1552 | /***********************************************************//** | |
1553 | +*/ | |
1554 | +UNIV_INTERN | |
1555 | +que_thr_t* | |
1556 | +dict_insert_stats_step( | |
1557 | +/*===================*/ | |
1558 | + que_thr_t* thr); | |
1559 | +/***********************************************************//** | |
1560 | Creates an index. This is a high-level function used in SQL execution | |
1561 | graphs. | |
1562 | @return query thread to run next or NULL */ | |
1563 | @@ -170,6 +185,7 @@ | |
1564 | ins_node_t* field_def; /* child node which does the inserts of | |
1565 | the field definitions; the row to be inserted | |
1566 | is built by the parent node */ | |
1567 | + ins_node_t* stats_def; | |
1568 | commit_node_t* commit_node; | |
1569 | /* child node which performs a commit after | |
1570 | a successful index creation */ | |
1571 | @@ -180,6 +196,7 @@ | |
1572 | dict_table_t* table; /*!< table which owns the index */ | |
1573 | dtuple_t* ind_row;/* index definition row built */ | |
1574 | ulint field_no;/* next field definition to insert */ | |
1575 | + ulint stats_no; | |
1576 | mem_heap_t* heap; /*!< memory heap used as auxiliary storage */ | |
1577 | }; | |
1578 | ||
1579 | @@ -189,6 +206,7 @@ | |
1580 | #define INDEX_CREATE_INDEX_TREE 3 | |
1581 | #define INDEX_COMMIT_WORK 4 | |
1582 | #define INDEX_ADD_TO_CACHE 5 | |
1583 | +#define INDEX_BUILD_STATS_COLS 6 | |
1584 | ||
1585 | #ifndef UNIV_NONINL | |
1586 | #include "dict0crea.ic" | |
1587 | diff -ruN a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h | |
1588 | --- a/storage/innobase/include/dict0dict.h 2010-12-03 15:48:03.073024387 +0900 | |
1589 | +++ b/storage/innobase/include/dict0dict.h 2010-12-03 17:19:24.888965622 +0900 | |
1590 | @@ -1084,10 +1084,11 @@ | |
1591 | dict_update_statistics( | |
1592 | /*===================*/ | |
1593 | dict_table_t* table, /*!< in/out: table */ | |
1594 | - ibool only_calc_if_missing_stats);/*!< in: only | |
1595 | + ibool only_calc_if_missing_stats, /*!< in: only | |
1596 | update/recalc the stats if they have | |
1597 | not been initialized yet, otherwise | |
1598 | do nothing */ | |
1599 | + ibool sync); | |
1600 | /********************************************************************//** | |
1601 | Reserves the dictionary system mutex for MySQL. */ | |
1602 | UNIV_INTERN | |
1603 | @@ -1202,6 +1203,7 @@ | |
1604 | dict_table_t* sys_columns; /*!< SYS_COLUMNS table */ | |
1605 | dict_table_t* sys_indexes; /*!< SYS_INDEXES table */ | |
1606 | dict_table_t* sys_fields; /*!< SYS_FIELDS table */ | |
1607 | + dict_table_t* sys_stats; /*!< SYS_STATS table */ | |
1608 | }; | |
1609 | #endif /* !UNIV_HOTBACKUP */ | |
1610 | ||
1611 | diff -ruN a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h | |
1612 | --- a/storage/innobase/include/dict0load.h 2010-11-03 07:01:13.000000000 +0900 | |
1613 | +++ b/storage/innobase/include/dict0load.h 2010-12-03 17:19:24.889947481 +0900 | |
1614 | @@ -41,6 +41,7 @@ | |
1615 | SYS_FIELDS, | |
1616 | SYS_FOREIGN, | |
1617 | SYS_FOREIGN_COLS, | |
1618 | + SYS_STATS, | |
1619 | ||
1620 | /* This must be last item. Defines the number of system tables. */ | |
1621 | SYS_NUM_SYSTEM_TABLES | |
1622 | @@ -319,6 +320,19 @@ | |
1623 | const char** ref_col_name, /*!< out: referenced column name | |
1624 | in referenced table */ | |
1625 | ulint* pos); /*!< out: column position */ | |
1626 | +/********************************************************************//** | |
1627 | +This function parses a SYS_STATS record and extract necessary | |
1628 | +information from the record and return to caller. | |
1629 | +@return error message, or NULL on success */ | |
1630 | +UNIV_INTERN | |
1631 | +const char* | |
1632 | +dict_process_sys_stats_rec( | |
1633 | +/*=============================*/ | |
1634 | + mem_heap_t* heap, /*!< in/out: heap memory */ | |
1635 | + const rec_t* rec, /*!< in: current SYS_STATS rec */ | |
1636 | + index_id_t* index_id, /*!< out: INDEX_ID */ | |
1637 | + ulint* key_cols, /*!< out: KEY_COLS */ | |
1638 | + ib_uint64_t* diff_vals); /*!< out: DIFF_VALS */ | |
1639 | #ifndef UNIV_NONINL | |
1640 | #include "dict0load.ic" | |
1641 | #endif | |
b4e1fa2c AM |
1642 | diff -ruN a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h |
1643 | --- a/storage/innobase/include/que0que.h 2010-11-03 07:01:13.000000000 +0900 | |
1644 | +++ b/storage/innobase/include/que0que.h 2010-12-03 17:19:24.892947946 +0900 | |
1645 | @@ -492,6 +492,8 @@ | |
1646 | #define QUE_NODE_CALL 31 | |
1647 | #define QUE_NODE_EXIT 32 | |
1648 | ||
1649 | +#define QUE_NODE_INSERT_STATS 34 | |
1650 | + | |
1651 | /* Query thread states */ | |
1652 | #define QUE_THR_RUNNING 1 | |
1653 | #define QUE_THR_PROCEDURE_WAIT 2 | |
b4e1fa2c AM |
1654 | diff -ruN a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h |
1655 | --- a/storage/innobase/include/row0mysql.h 2010-11-03 07:01:13.000000000 +0900 | |
1656 | +++ b/storage/innobase/include/row0mysql.h 2010-12-03 17:19:24.904973020 +0900 | |
1657 | @@ -387,6 +387,14 @@ | |
1658 | then checked for not being too | |
1659 | large. */ | |
1660 | /*********************************************************************//** | |
1661 | +*/ | |
1662 | +UNIV_INTERN | |
1663 | +int | |
1664 | +row_insert_stats_for_mysql( | |
1665 | +/*=======================*/ | |
1666 | + dict_index_t* index, | |
1667 | + trx_t* trx); | |
1668 | +/*********************************************************************//** | |
1669 | Scans a table create SQL string and adds to the data dictionary | |
1670 | the foreign key constraints declared in the string. This function | |
1671 | should be called after the indexes for a table have been created. | |
1672 | diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h | |
1673 | --- a/storage/innobase/include/srv0srv.h 2010-12-03 15:53:54.622036720 +0900 | |
1674 | +++ b/storage/innobase/include/srv0srv.h 2010-12-03 17:19:24.906953188 +0900 | |
df1b5770 | 1675 | @@ -214,6 +214,9 @@ |
b4e1fa2c AM |
1676 | extern ibool srv_innodb_status; |
1677 | ||
1678 | extern unsigned long long srv_stats_sample_pages; | |
b4e1fa2c AM |
1679 | +extern ulint srv_stats_auto_update; |
1680 | +extern ulint srv_stats_update_need_lock; | |
1681 | +extern ibool srv_use_sys_stats_table; | |
1682 | ||
1683 | extern ibool srv_use_doublewrite_buf; | |
1684 | extern ibool srv_use_checksums; | |
b4e1fa2c AM |
1685 | diff -ruN a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c |
1686 | --- a/storage/innobase/que/que0que.c 2010-11-03 07:01:13.000000000 +0900 | |
1687 | +++ b/storage/innobase/que/que0que.c 2010-12-03 17:19:24.910953422 +0900 | |
1688 | @@ -621,11 +621,21 @@ | |
1689 | ||
1690 | que_graph_free_recursive(cre_ind->ind_def); | |
1691 | que_graph_free_recursive(cre_ind->field_def); | |
1692 | + if (srv_use_sys_stats_table) | |
1693 | + que_graph_free_recursive(cre_ind->stats_def); | |
1694 | que_graph_free_recursive(cre_ind->commit_node); | |
1695 | ||
1696 | mem_heap_free(cre_ind->heap); | |
1697 | ||
1698 | break; | |
1699 | + case QUE_NODE_INSERT_STATS: | |
1700 | + cre_ind = node; | |
1701 | + | |
1702 | + que_graph_free_recursive(cre_ind->stats_def); | |
1703 | + que_graph_free_recursive(cre_ind->commit_node); | |
1704 | + | |
1705 | + mem_heap_free(cre_ind->heap); | |
1706 | + break; | |
1707 | case QUE_NODE_PROC: | |
1708 | que_graph_free_stat_list(((proc_node_t*)node)->stat_list); | |
1709 | ||
1710 | @@ -1138,6 +1148,8 @@ | |
1711 | str = "CREATE TABLE"; | |
1712 | } else if (type == QUE_NODE_CREATE_INDEX) { | |
1713 | str = "CREATE INDEX"; | |
1714 | + } else if (type == QUE_NODE_INSERT_STATS) { | |
1715 | + str = "INSERT TO SYS_STATS"; | |
1716 | } else if (type == QUE_NODE_FOR) { | |
1717 | str = "FOR LOOP"; | |
1718 | } else if (type == QUE_NODE_RETURN) { | |
1719 | @@ -1255,6 +1267,8 @@ | |
1720 | thr = dict_create_table_step(thr); | |
1721 | } else if (type == QUE_NODE_CREATE_INDEX) { | |
1722 | thr = dict_create_index_step(thr); | |
1723 | + } else if (type == QUE_NODE_INSERT_STATS) { | |
1724 | + thr = dict_insert_stats_step(thr); | |
1725 | } else if (type == QUE_NODE_ROW_PRINTF) { | |
1726 | thr = row_printf_step(thr); | |
1727 | } else { | |
b4e1fa2c AM |
1728 | diff -ruN a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c |
1729 | --- a/storage/innobase/row/row0merge.c 2010-11-03 07:01:13.000000000 +0900 | |
1730 | +++ b/storage/innobase/row/row0merge.c 2010-12-03 17:19:24.914955391 +0900 | |
1731 | @@ -2020,6 +2020,8 @@ | |
1732 | "UPDATE SYS_INDEXES SET NAME=CONCAT('" | |
1733 | TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n" | |
1734 | "COMMIT WORK;\n" | |
1735 | + /* Drop the statistics of the index. */ | |
1736 | + "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n" | |
1737 | /* Drop the field definitions of the index. */ | |
1738 | "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n" | |
1739 | /* Drop the index definition and the B-tree. */ | |
1740 | diff -ruN a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c | |
1741 | --- a/storage/innobase/row/row0mysql.c 2010-11-03 07:01:13.000000000 +0900 | |
1742 | +++ b/storage/innobase/row/row0mysql.c 2010-12-03 17:19:24.918953476 +0900 | |
1743 | @@ -921,6 +921,9 @@ | |
1744 | ||
1745 | table->stat_modified_counter = counter + 1; | |
1746 | ||
1747 | + if (!srv_stats_auto_update) | |
1748 | + return; | |
1749 | + | |
1750 | /* Calculate new statistics if 1 / 16 of table has been modified | |
1751 | since the last time a statistics batch was run, or if | |
1752 | stat_modified_counter > 2 000 000 000 (to avoid wrap-around). | |
1753 | @@ -931,7 +934,7 @@ | |
1754 | || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) { | |
1755 | ||
1756 | dict_update_statistics(table, FALSE /* update even if stats | |
1757 | - are initialized */); | |
1758 | + are initialized */, TRUE); | |
1759 | } | |
1760 | } | |
1761 | ||
df1b5770 | 1762 | @@ -2105,6 +2108,45 @@ |
b4e1fa2c AM |
1763 | } |
1764 | ||
1765 | /*********************************************************************//** | |
1766 | +*/ | |
1767 | +UNIV_INTERN | |
1768 | +int | |
1769 | +row_insert_stats_for_mysql( | |
1770 | +/*=======================*/ | |
1771 | + dict_index_t* index, | |
1772 | + trx_t* trx) | |
1773 | +{ | |
1774 | + ind_node_t* node; | |
1775 | + mem_heap_t* heap; | |
1776 | + que_thr_t* thr; | |
1777 | + ulint err; | |
1778 | + | |
1779 | + ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); | |
1780 | + | |
1781 | + trx->op_info = "try to insert rows to SYS_STATS"; | |
1782 | + | |
1783 | + trx_start_if_not_started(trx); | |
1784 | + trx->error_state = DB_SUCCESS; | |
1785 | + | |
1786 | + heap = mem_heap_create(512); | |
1787 | + | |
1788 | + node = ind_insert_stats_graph_create(index, heap); | |
1789 | + | |
1790 | + thr = pars_complete_graph_for_exec(node, trx, heap); | |
1791 | + | |
1792 | + ut_a(thr == que_fork_start_command(que_node_get_parent(thr))); | |
1793 | + que_run_threads(thr); | |
1794 | + | |
1795 | + err = trx->error_state; | |
1796 | + | |
1797 | + que_graph_free((que_t*) que_node_get_parent(thr)); | |
1798 | + | |
1799 | + trx->op_info = ""; | |
1800 | + | |
1801 | + return((int) err); | |
1802 | +} | |
1803 | + | |
1804 | +/*********************************************************************//** | |
1805 | Scans a table create SQL string and adds to the data dictionary | |
1806 | the foreign key constraints declared in the string. This function | |
1807 | should be called after the indexes for a table have been created. | |
df1b5770 | 1808 | @@ -3024,7 +3066,7 @@ |
b4e1fa2c AM |
1809 | dict_table_autoinc_initialize(table, 1); |
1810 | dict_table_autoinc_unlock(table); | |
1811 | dict_update_statistics(table, FALSE /* update even if stats are | |
1812 | - initialized */); | |
1813 | + initialized */, TRUE); | |
1814 | ||
1815 | trx_commit_for_mysql(trx); | |
1816 | ||
df1b5770 | 1817 | @@ -3326,6 +3368,8 @@ |
b4e1fa2c AM |
1818 | " IF (SQL % NOTFOUND) THEN\n" |
1819 | " found := 0;\n" | |
1820 | " ELSE\n" | |
1821 | + " DELETE FROM SYS_STATS\n" | |
1822 | + " WHERE INDEX_ID = index_id;\n" | |
1823 | " DELETE FROM SYS_FIELDS\n" | |
1824 | " WHERE INDEX_ID = index_id;\n" | |
1825 | " DELETE FROM SYS_INDEXES\n" | |
1826 | diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c | |
1827 | --- a/storage/innobase/srv/srv0srv.c 2010-12-03 15:53:54.625288512 +0900 | |
1828 | +++ b/storage/innobase/srv/srv0srv.c 2010-12-03 17:19:24.922953561 +0900 | |
df1b5770 | 1829 | @@ -402,6 +402,9 @@ |
b4e1fa2c AM |
1830 | /* When estimating number of different key values in an index, sample |
1831 | this many index pages */ | |
1832 | UNIV_INTERN unsigned long long srv_stats_sample_pages = 8; | |
b4e1fa2c AM |
1833 | +UNIV_INTERN ulint srv_stats_auto_update = 1; |
1834 | +UNIV_INTERN ulint srv_stats_update_need_lock = 1; | |
1835 | +UNIV_INTERN ibool srv_use_sys_stats_table = FALSE; | |
1836 | ||
1837 | UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE; | |
1838 | UNIV_INTERN ibool srv_use_checksums = TRUE; |