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