]> git.pld-linux.org Git - packages/mysql.git/blob - innodb_stats.patch
move status action to status function
[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 @@ -1177,6 +1316,66 @@
282                 return(NULL);
283         }
284  
285 +       thr->run_node = que_node_get_parent(node);
286 +
287 +       return(thr);
288 +}
289 +
290 +/****************************************************************//**
291 +*/
292 +UNIV_INTERN
293 +que_thr_t*
294 +dict_insert_stats_step(
295 +/*===================*/
296 +       que_thr_t*      thr)    /*!< in: query thread */
297 +{
298 +       ind_node_t*     node;
299 +       ulint           err     = DB_ERROR;
300 +       trx_t*          trx;
301 +
302 +       ut_ad(thr);
303 +
304 +       trx = thr_get_trx(thr);
305 +
306 +       node = thr->run_node;
307 +
308 +       if (thr->prev_node == que_node_get_parent(node)) {
309 +               node->state = INDEX_BUILD_STATS_COLS;
310 +       }
311 +
312 +       if (node->state == INDEX_BUILD_STATS_COLS) {
313 +               if (node->stats_no <= dict_index_get_n_unique(node->index)) {
314 +
315 +                       err = dict_build_stats_def_step(node);
316 +
317 +                       if (err != DB_SUCCESS) {
318 +
319 +                               goto function_exit;
320 +                       }
321 +
322 +                       node->stats_no++;
323 +
324 +                       thr->run_node = node->stats_def;
325 +
326 +                       return(thr);
327 +               } else {
328 +                       node->state = INDEX_COMMIT_WORK;
329 +               }
330 +       }
331 +
332 +       if (node->state == INDEX_COMMIT_WORK) {
333 +
334 +               /* do not commit transaction here for now */
335 +       }
336 +
337 +function_exit:
338 +       trx->error_state = err;
339 +
340 +       if (err == DB_SUCCESS) {
341 +       } else {
342 +               return(NULL);
343 +       }
344 +
345         thr->run_node = que_node_get_parent(node);
346  
347         return(thr);
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 @@ -4354,6 +4354,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 @@ -4361,10 +4650,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 @@ -4381,6 +4671,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 @@ -4445,6 +4756,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 @@ -4462,6 +4778,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 @@ -4539,7 +4927,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  /* If this flag is TRUE, then we will load the cluster index's (and tables')
809 @@ -348,12 +349,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 @@ -587,6 +589,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 @@ -2468,6 +2469,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 @@ -5256,6 +5259,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 @@ -5591,6 +5598,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 @@ -5644,6 +5655,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 @@ -5965,6 +5980,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 @@ -6196,6 +6216,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 @@ -8149,11 +8174,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 @@ -8238,7 +8287,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 @@ -11511,6 +11560,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 @@ -11883,6 +11952,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 @@ -11957,7 +12029,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 @@ -3511,6 +3512,225 @@
1082         STRUCT_FLD(flags, 0UL)
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 +       /* flags for plugin */
1300 +       /* unsigned long */
1301 +       STRUCT_FLD(flags, 0UL)
1302 +};
1303 +
1304  /***********************************************************************
1305  */
1306  static ST_FIELD_INFO   i_s_innodb_rseg_fields_info[] =
1307 @@ -3677,3 +3897,349 @@
1308         /* unsigned long */
1309         STRUCT_FLD(flags, 0UL),
1310  };
1311 +
1312 +/***********************************************************************
1313 +*/
1314 +static ST_FIELD_INFO   i_s_innodb_table_stats_info[] =
1315 +{
1316 +       {STRUCT_FLD(field_name,         "table_schema"),
1317 +        STRUCT_FLD(field_length,       NAME_LEN),
1318 +        STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
1319 +        STRUCT_FLD(value,              0),
1320 +        STRUCT_FLD(field_flags,        0),
1321 +        STRUCT_FLD(old_name,           ""),
1322 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1323 +
1324 +       {STRUCT_FLD(field_name,         "table_name"),
1325 +        STRUCT_FLD(field_length,       NAME_LEN),
1326 +        STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
1327 +        STRUCT_FLD(value,              0),
1328 +        STRUCT_FLD(field_flags,        0),
1329 +        STRUCT_FLD(old_name,           ""),
1330 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1331 +
1332 +       {STRUCT_FLD(field_name,         "rows"),
1333 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1334 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1335 +        STRUCT_FLD(value,              0),
1336 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1337 +        STRUCT_FLD(old_name,           ""),
1338 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1339 +
1340 +       {STRUCT_FLD(field_name,         "clust_size"),
1341 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1342 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1343 +        STRUCT_FLD(value,              0),
1344 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1345 +        STRUCT_FLD(old_name,           ""),
1346 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1347 +
1348 +       {STRUCT_FLD(field_name,         "other_size"),
1349 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1350 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1351 +        STRUCT_FLD(value,              0),
1352 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1353 +        STRUCT_FLD(old_name,           ""),
1354 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1355 +
1356 +       {STRUCT_FLD(field_name,         "modified"),
1357 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1358 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1359 +        STRUCT_FLD(value,              0),
1360 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1361 +        STRUCT_FLD(old_name,           ""),
1362 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1363 +
1364 +       END_OF_ST_FIELD_INFO
1365 +};
1366 +
1367 +static ST_FIELD_INFO   i_s_innodb_index_stats_info[] =
1368 +{
1369 +       {STRUCT_FLD(field_name,         "table_schema"),
1370 +        STRUCT_FLD(field_length,       NAME_LEN),
1371 +        STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
1372 +        STRUCT_FLD(value,              0),
1373 +        STRUCT_FLD(field_flags,        0),
1374 +        STRUCT_FLD(old_name,           ""),
1375 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1376 +
1377 +       {STRUCT_FLD(field_name,         "table_name"),
1378 +        STRUCT_FLD(field_length,       NAME_LEN),
1379 +        STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
1380 +        STRUCT_FLD(value,              0),
1381 +        STRUCT_FLD(field_flags,        0),
1382 +        STRUCT_FLD(old_name,           ""),
1383 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1384 +
1385 +       {STRUCT_FLD(field_name,         "index_name"),
1386 +        STRUCT_FLD(field_length,       NAME_LEN),
1387 +        STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
1388 +        STRUCT_FLD(value,              0),
1389 +        STRUCT_FLD(field_flags,        0),
1390 +        STRUCT_FLD(old_name,           ""),
1391 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1392 +
1393 +       {STRUCT_FLD(field_name,         "fields"),
1394 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1395 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1396 +        STRUCT_FLD(value,              0),
1397 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1398 +        STRUCT_FLD(old_name,           ""),
1399 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1400 +
1401 +       {STRUCT_FLD(field_name,         "rows_per_key"),
1402 +        STRUCT_FLD(field_length,       256),
1403 +        STRUCT_FLD(field_type,         MYSQL_TYPE_STRING),
1404 +        STRUCT_FLD(value,              0),
1405 +        STRUCT_FLD(field_flags,        0),
1406 +        STRUCT_FLD(old_name,           ""),
1407 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1408 +
1409 +       {STRUCT_FLD(field_name,         "index_total_pages"),
1410 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1411 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1412 +        STRUCT_FLD(value,              0),
1413 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1414 +        STRUCT_FLD(old_name,           ""),
1415 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1416 +
1417 +       {STRUCT_FLD(field_name,         "index_leaf_pages"),
1418 +        STRUCT_FLD(field_length,       MY_INT64_NUM_DECIMAL_DIGITS),
1419 +        STRUCT_FLD(field_type,         MYSQL_TYPE_LONGLONG),
1420 +        STRUCT_FLD(value,              0),
1421 +        STRUCT_FLD(field_flags,        MY_I_S_UNSIGNED),
1422 +        STRUCT_FLD(old_name,           ""),
1423 +        STRUCT_FLD(open_method,        SKIP_OPEN_TABLE)},
1424 +
1425 +       END_OF_ST_FIELD_INFO
1426 +};
1427 +
1428 +static
1429 +int
1430 +i_s_innodb_table_stats_fill(
1431 +/*========================*/
1432 +       THD*            thd,
1433 +       TABLE_LIST*     tables,
1434 +       COND*           cond)
1435 +{
1436 +       TABLE*  i_s_table       = (TABLE *) tables->table;
1437 +       int     status  = 0;
1438 +       dict_table_t*   table;
1439 +
1440 +       DBUG_ENTER("i_s_innodb_table_stats_fill");
1441 +
1442 +       /* deny access to non-superusers */
1443 +       if (check_global_access(thd, PROCESS_ACL)) {
1444 +               DBUG_RETURN(0);
1445 +       }
1446 +
1447 +       mutex_enter(&(dict_sys->mutex));
1448 +
1449 +       table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1450 +
1451 +       while (table) {
1452 +               char    buf[NAME_LEN * 2 + 2];
1453 +               char*   ptr;
1454 +
1455 +               if (table->stat_clustered_index_size == 0) {
1456 +                       table = UT_LIST_GET_NEXT(table_LRU, table);
1457 +                       continue;
1458 +               }
1459 +
1460 +               buf[NAME_LEN * 2 + 1] = 0;
1461 +               strncpy(buf, table->name, NAME_LEN * 2 + 1);
1462 +               ptr = strchr(buf, '/');
1463 +               if (ptr) {
1464 +                       *ptr = '\0';
1465 +                       ++ptr;
1466 +               } else {
1467 +                       ptr = buf;
1468 +               }
1469 +
1470 +               field_store_string(i_s_table->field[0], buf);
1471 +               field_store_string(i_s_table->field[1], ptr);
1472 +               i_s_table->field[2]->store(table->stat_n_rows);
1473 +               i_s_table->field[3]->store(table->stat_clustered_index_size);
1474 +               i_s_table->field[4]->store(table->stat_sum_of_other_index_sizes);
1475 +               i_s_table->field[5]->store(table->stat_modified_counter);
1476 +
1477 +               if (schema_table_store_record(thd, i_s_table)) {
1478 +                       status = 1;
1479 +                       break;
1480 +               }
1481 +
1482 +               table = UT_LIST_GET_NEXT(table_LRU, table);
1483 +       }
1484 +
1485 +       mutex_exit(&(dict_sys->mutex));
1486 +
1487 +       DBUG_RETURN(status);
1488 +}
1489 +
1490 +static
1491 +int
1492 +i_s_innodb_index_stats_fill(
1493 +/*========================*/
1494 +       THD*            thd,
1495 +       TABLE_LIST*     tables,
1496 +       COND*           cond)
1497 +{
1498 +       TABLE*  i_s_table       = (TABLE *) tables->table;
1499 +       int     status  = 0;
1500 +       dict_table_t*   table;
1501 +       dict_index_t*   index;
1502 +
1503 +       DBUG_ENTER("i_s_innodb_index_stats_fill");
1504 +
1505 +       /* deny access to non-superusers */
1506 +       if (check_global_access(thd, PROCESS_ACL)) {
1507 +               DBUG_RETURN(0);
1508 +       }
1509 +
1510 +       mutex_enter(&(dict_sys->mutex));
1511 +
1512 +       table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1513 +
1514 +       while (table) {
1515 +               if (table->stat_clustered_index_size == 0) {
1516 +                       table = UT_LIST_GET_NEXT(table_LRU, table);
1517 +                       continue;
1518 +               }
1519 +
1520 +               ib_int64_t      n_rows = table->stat_n_rows;
1521 +
1522 +               if (n_rows < 0) {
1523 +                       n_rows = 0;
1524 +               }
1525 +
1526 +               index = dict_table_get_first_index(table);
1527 +
1528 +               while (index) {
1529 +                       char    buff[256+1];
1530 +                       char    row_per_keys[256+1];
1531 +                       char    buf[NAME_LEN * 2 + 2];
1532 +                       char*   ptr;
1533 +                       ulint   i;
1534 +
1535 +                       buf[NAME_LEN * 2 + 1] = 0;
1536 +                       strncpy(buf, table->name, NAME_LEN * 2 + 1);
1537 +                       ptr = strchr(buf, '/');
1538 +                       if (ptr) {
1539 +                               *ptr = '\0';
1540 +                               ++ptr;
1541 +                       } else {
1542 +                               ptr = buf;
1543 +                       }
1544 +
1545 +                       field_store_string(i_s_table->field[0], buf);
1546 +                       field_store_string(i_s_table->field[1], ptr);
1547 +                       field_store_string(i_s_table->field[2], index->name);
1548 +                       i_s_table->field[3]->store(index->n_uniq);
1549 +
1550 +                       row_per_keys[0] = '\0';
1551 +
1552 +                       /* It is remained optimistic operation still for now */
1553 +                       //dict_index_stat_mutex_enter(index);
1554 +                       if (index->stat_n_diff_key_vals) {
1555 +                               for (i = 1; i <= index->n_uniq; i++) {
1556 +                                       ib_int64_t      rec_per_key;
1557 +                                       if (index->stat_n_diff_key_vals[i]) {
1558 +                                               rec_per_key = n_rows / index->stat_n_diff_key_vals[i];
1559 +                                       } else {
1560 +                                               rec_per_key = n_rows;
1561 +                                       }
1562 +                                       ut_snprintf(buff, 256, (i == index->n_uniq)?"%llu":"%llu, ",
1563 +                                                rec_per_key);
1564 +                                       strncat(row_per_keys, buff, 256 - strlen(row_per_keys));
1565 +                               }
1566 +                       }
1567 +                       //dict_index_stat_mutex_exit(index);
1568 +
1569 +                       field_store_string(i_s_table->field[4], row_per_keys);
1570 +
1571 +                       i_s_table->field[5]->store(index->stat_index_size);
1572 +                       i_s_table->field[6]->store(index->stat_n_leaf_pages);
1573 +
1574 +                       if (schema_table_store_record(thd, i_s_table)) {
1575 +                               status = 1;
1576 +                               break;
1577 +                       }
1578 +
1579 +                       index = dict_table_get_next_index(index);
1580 +               }
1581 +
1582 +               if (status == 1) {
1583 +                       break;
1584 +               }
1585 +
1586 +               table = UT_LIST_GET_NEXT(table_LRU, table);
1587 +       }
1588 +
1589 +       mutex_exit(&(dict_sys->mutex));
1590 +
1591 +       DBUG_RETURN(status);
1592 +}
1593 +
1594 +static
1595 +int
1596 +i_s_innodb_table_stats_init(
1597 +/*========================*/
1598 +       void*   p)
1599 +{
1600 +       DBUG_ENTER("i_s_innodb_table_stats_init");
1601 +       ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1602 +
1603 +       schema->fields_info = i_s_innodb_table_stats_info;
1604 +       schema->fill_table = i_s_innodb_table_stats_fill;
1605 +
1606 +       DBUG_RETURN(0);
1607 +}
1608 +
1609 +static
1610 +int
1611 +i_s_innodb_index_stats_init(
1612 +/*========================*/
1613 +       void*   p)
1614 +{
1615 +       DBUG_ENTER("i_s_innodb_index_stats_init");
1616 +       ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1617 +
1618 +       schema->fields_info = i_s_innodb_index_stats_info;
1619 +       schema->fill_table = i_s_innodb_index_stats_fill;
1620 +
1621 +       DBUG_RETURN(0);
1622 +}
1623 +
1624 +UNIV_INTERN struct st_mysql_plugin     i_s_innodb_table_stats =
1625 +{
1626 +       STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1627 +       STRUCT_FLD(info, &i_s_info),
1628 +       STRUCT_FLD(name, "INNODB_TABLE_STATS"),
1629 +       STRUCT_FLD(author, "Percona"),
1630 +       STRUCT_FLD(descr, "InnoDB table statistics in memory"),
1631 +       STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1632 +       STRUCT_FLD(init, i_s_innodb_table_stats_init),
1633 +       STRUCT_FLD(deinit, i_s_common_deinit),
1634 +       STRUCT_FLD(version, 0x0100 /* 1.0 */),
1635 +       STRUCT_FLD(status_vars, NULL),
1636 +       STRUCT_FLD(system_vars, NULL),
1637 +       STRUCT_FLD(__reserved1, NULL),
1638 +       STRUCT_FLD(flags, 0UL)
1639 +};
1640 +
1641 +UNIV_INTERN struct st_mysql_plugin     i_s_innodb_index_stats =
1642 +{
1643 +       STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
1644 +       STRUCT_FLD(info, &i_s_info),
1645 +       STRUCT_FLD(name, "INNODB_INDEX_STATS"),
1646 +       STRUCT_FLD(author, "Percona"),
1647 +       STRUCT_FLD(descr, "InnoDB index statistics in memory"),
1648 +       STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
1649 +       STRUCT_FLD(init, i_s_innodb_index_stats_init),
1650 +       STRUCT_FLD(deinit, i_s_common_deinit),
1651 +       STRUCT_FLD(version, 0x0100 /* 1.0 */),
1652 +       STRUCT_FLD(status_vars, NULL),
1653 +       STRUCT_FLD(system_vars, NULL),
1654 +       STRUCT_FLD(__reserved1, NULL),
1655 +       STRUCT_FLD(flags, 0UL)
1656 +};
1657 --- a/storage/innobase/handler/i_s.h
1658 +++ b/storage/innobase/handler/i_s.h
1659 @@ -43,5 +43,8 @@
1660  extern struct st_mysql_plugin   i_s_innodb_sys_foreign;
1661  extern struct st_mysql_plugin   i_s_innodb_sys_foreign_cols;
1662  extern struct st_mysql_plugin  i_s_innodb_rseg;
1663 +extern struct st_mysql_plugin  i_s_innodb_sys_stats;
1664 +extern struct st_mysql_plugin  i_s_innodb_table_stats;
1665 +extern struct st_mysql_plugin  i_s_innodb_index_stats;
1666  
1667  #endif /* i_s_h */
1668 --- a/storage/innobase/include/dict0boot.h
1669 +++ b/storage/innobase/include/dict0boot.h
1670 @@ -104,6 +104,7 @@
1671  #define DICT_COLUMNS_ID                2
1672  #define DICT_INDEXES_ID                3
1673  #define DICT_FIELDS_ID         4
1674 +#define DICT_STATS_ID          6
1675  /* The following is a secondary index on SYS_TABLES */
1676  #define DICT_TABLE_IDS_ID      5
1677  
1678 @@ -131,10 +132,13 @@
1679  #define        DICT_HDR_INDEXES        44      /* Root of the index index tree */
1680  #define        DICT_HDR_FIELDS         48      /* Root of the index field
1681                                         index tree */
1682 +#define        DICT_HDR_STATS          52      /* Root of the stats tree */
1683  
1684  #define DICT_HDR_FSEG_HEADER   56      /* Segment header for the tablespace
1685                                         segment into which the dictionary
1686                                         header is created */
1687 +
1688 +#define        DICT_HDR_XTRADB_MARK    256     /* Flag to distinguish expansion of XtraDB */
1689  /*-------------------------------------------------------------*/
1690  
1691  /* The field numbers in the SYS_TABLES clustered index */
1692 @@ -146,11 +150,16 @@
1693  #define DICT_SYS_INDEXES_TYPE_FIELD     6
1694  #define DICT_SYS_INDEXES_NAME_FIELD     4
1695  
1696 +#define DICT_SYS_STATS_DIFF_VALS_FIELD  4
1697 +#define DICT_SYS_STATS_NON_NULL_VALS_FIELD     5
1698 +
1699  /* When a row id which is zero modulo this number (which must be a power of
1700  two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is
1701  updated */
1702  #define DICT_HDR_ROW_ID_WRITE_MARGIN   256
1703  
1704 +#define DICT_HDR_XTRADB_FLAG           0x5854524144425F31ULL   /* "XTRADB_1" */
1705 +
1706  #ifndef UNIV_NONINL
1707  #include "dict0boot.ic"
1708  #endif
1709 --- a/storage/innobase/include/dict0crea.h
1710 +++ b/storage/innobase/include/dict0crea.h
1711 @@ -53,6 +53,14 @@
1712         dict_index_t*   index,  /*!< in: index to create, built as a memory data
1713                                 structure */
1714         mem_heap_t*     heap);  /*!< in: heap where created */
1715 +/*********************************************************************//**
1716 +*/
1717 +UNIV_INTERN
1718 +ind_node_t*
1719 +ind_insert_stats_graph_create(
1720 +/*==========================*/
1721 +       dict_index_t*   index,
1722 +       mem_heap_t*     heap);
1723  /***********************************************************//**
1724  Creates a table. This is a high-level function used in SQL execution graphs.
1725  @return        query thread to run next or NULL */
1726 @@ -62,6 +70,13 @@
1727  /*===================*/
1728         que_thr_t*      thr);   /*!< in: query thread */
1729  /***********************************************************//**
1730 +*/
1731 +UNIV_INTERN
1732 +que_thr_t*
1733 +dict_insert_stats_step(
1734 +/*===================*/
1735 +       que_thr_t*      thr);
1736 +/***********************************************************//**
1737  Creates an index. This is a high-level function used in SQL execution
1738  graphs.
1739  @return        query thread to run next or NULL */
1740 @@ -170,6 +185,7 @@
1741         ins_node_t*     field_def; /* child node which does the inserts of
1742                                 the field definitions; the row to be inserted
1743                                 is built by the parent node  */
1744 +       ins_node_t*     stats_def;
1745         commit_node_t*  commit_node;
1746                                 /* child node which performs a commit after
1747                                 a successful index creation */
1748 @@ -180,6 +196,7 @@
1749         dict_table_t*   table;  /*!< table which owns the index */
1750         dtuple_t*       ind_row;/* index definition row built */
1751         ulint           field_no;/* next field definition to insert */
1752 +       ulint           stats_no;
1753         mem_heap_t*     heap;   /*!< memory heap used as auxiliary storage */
1754  };
1755  
1756 @@ -189,6 +206,7 @@
1757  #define        INDEX_CREATE_INDEX_TREE 3
1758  #define        INDEX_COMMIT_WORK       4
1759  #define        INDEX_ADD_TO_CACHE      5
1760 +#define        INDEX_BUILD_STATS_COLS  6
1761  
1762  #ifndef UNIV_NONINL
1763  #include "dict0crea.ic"
1764 --- a/storage/innobase/include/dict0dict.h
1765 +++ b/storage/innobase/include/dict0dict.h
1766 @@ -1126,10 +1126,18 @@
1767  dict_update_statistics(
1768  /*===================*/
1769         dict_table_t*   table,          /*!< in/out: table */
1770 -       ibool           only_calc_if_missing_stats);/*!< in: only
1771 +       ibool           only_calc_if_missing_stats, /*!< in: only
1772                                         update/recalc the stats if they have
1773                                         not been initialized yet, otherwise
1774                                         do nothing */
1775 +       ibool           sync);
1776 +/*********************************************************************//**
1777 +*/
1778 +UNIV_INTERN
1779 +ibool
1780 +dict_is_older_statistics(
1781 +/*=====================*/
1782 +       dict_index_t*   index);
1783  /********************************************************************//**
1784  Reserves the dictionary system mutex for MySQL. */
1785  UNIV_INTERN
1786 @@ -1244,6 +1252,7 @@
1787         dict_table_t*   sys_columns;    /*!< SYS_COLUMNS table */
1788         dict_table_t*   sys_indexes;    /*!< SYS_INDEXES table */
1789         dict_table_t*   sys_fields;     /*!< SYS_FIELDS table */
1790 +       dict_table_t*   sys_stats;      /*!< SYS_STATS table */
1791  };
1792  #endif /* !UNIV_HOTBACKUP */
1793  
1794 --- a/storage/innobase/include/dict0load.h
1795 +++ b/storage/innobase/include/dict0load.h
1796 @@ -41,6 +41,7 @@
1797         SYS_FIELDS,
1798         SYS_FOREIGN,
1799         SYS_FOREIGN_COLS,
1800 +       SYS_STATS,
1801  
1802         /* This must be last item. Defines the number of system tables. */
1803         SYS_NUM_SYSTEM_TABLES
1804 @@ -327,6 +328,20 @@
1805         const char**    ref_col_name,   /*!< out: referenced column name
1806                                         in referenced table */
1807         ulint*          pos);           /*!< out: column position */
1808 +/********************************************************************//**
1809 +This function parses a SYS_STATS record and extract necessary
1810 +information from the record and return to caller.
1811 +@return error message, or NULL on success */
1812 +UNIV_INTERN
1813 +const char*
1814 +dict_process_sys_stats_rec(
1815 +/*=============================*/
1816 +       mem_heap_t*     heap,           /*!< in/out: heap memory */
1817 +       const rec_t*    rec,            /*!< in: current SYS_STATS rec */
1818 +       index_id_t*     index_id,       /*!< out: INDEX_ID */
1819 +       ulint*          key_cols,       /*!< out: KEY_COLS */
1820 +       ib_uint64_t*    diff_vals,      /*!< out: DIFF_VALS */
1821 +       ib_uint64_t*    non_null_vals); /*!< out: NON_NULL_VALS */
1822  #ifndef UNIV_NONINL
1823  #include "dict0load.ic"
1824  #endif
1825 --- a/storage/innobase/include/que0que.h
1826 +++ b/storage/innobase/include/que0que.h
1827 @@ -492,6 +492,8 @@
1828  #define QUE_NODE_CALL          31
1829  #define QUE_NODE_EXIT          32
1830  
1831 +#define QUE_NODE_INSERT_STATS  34
1832 +
1833  /* Query thread states */
1834  #define QUE_THR_RUNNING                1
1835  #define QUE_THR_PROCEDURE_WAIT 2
1836 --- a/storage/innobase/include/row0mysql.h
1837 +++ b/storage/innobase/include/row0mysql.h
1838 @@ -387,6 +387,22 @@
1839                                         then checked for not being too
1840                                         large. */
1841  /*********************************************************************//**
1842 +*/
1843 +UNIV_INTERN
1844 +int
1845 +row_insert_stats_for_mysql(
1846 +/*=======================*/
1847 +       dict_index_t*   index,
1848 +       trx_t*          trx);
1849 +/*********************************************************************//**
1850 +*/
1851 +UNIV_INTERN
1852 +int
1853 +row_delete_stats_for_mysql(
1854 +/*=======================*/
1855 +       dict_index_t*   index,
1856 +       trx_t*          trx);
1857 +/*********************************************************************//**
1858  Scans a table create SQL string and adds to the data dictionary
1859  the foreign key constraints declared in the string. This function
1860  should be called after the indexes for a table have been created.
1861 --- a/storage/innobase/include/srv0srv.h
1862 +++ b/storage/innobase/include/srv0srv.h
1863 @@ -216,6 +216,9 @@
1864  extern ibool   srv_innodb_status;
1865  
1866  extern unsigned long long      srv_stats_sample_pages;
1867 +extern ulint   srv_stats_auto_update;
1868 +extern ulint   srv_stats_update_need_lock;
1869 +extern ibool   srv_use_sys_stats_table;
1870  
1871  extern ibool   srv_use_doublewrite_buf;
1872  extern ibool   srv_use_checksums;
1873 --- a/storage/innobase/que/que0que.c
1874 +++ b/storage/innobase/que/que0que.c
1875 @@ -621,11 +621,21 @@
1876  
1877                 que_graph_free_recursive(cre_ind->ind_def);
1878                 que_graph_free_recursive(cre_ind->field_def);
1879 +               if (srv_use_sys_stats_table)
1880 +                       que_graph_free_recursive(cre_ind->stats_def);
1881                 que_graph_free_recursive(cre_ind->commit_node);
1882  
1883                 mem_heap_free(cre_ind->heap);
1884  
1885                 break;
1886 +       case QUE_NODE_INSERT_STATS:
1887 +               cre_ind = node;
1888 +
1889 +               que_graph_free_recursive(cre_ind->stats_def);
1890 +               que_graph_free_recursive(cre_ind->commit_node);
1891 +
1892 +               mem_heap_free(cre_ind->heap);
1893 +               break;
1894         case QUE_NODE_PROC:
1895                 que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
1896  
1897 @@ -1138,6 +1148,8 @@
1898                 str = "CREATE TABLE";
1899         } else if (type == QUE_NODE_CREATE_INDEX) {
1900                 str = "CREATE INDEX";
1901 +       } else if (type == QUE_NODE_INSERT_STATS) {
1902 +               str = "INSERT TO SYS_STATS";
1903         } else if (type == QUE_NODE_FOR) {
1904                 str = "FOR LOOP";
1905         } else if (type == QUE_NODE_RETURN) {
1906 @@ -1255,6 +1267,8 @@
1907                 thr = dict_create_table_step(thr);
1908         } else if (type == QUE_NODE_CREATE_INDEX) {
1909                 thr = dict_create_index_step(thr);
1910 +       } else if (type == QUE_NODE_INSERT_STATS) {
1911 +               thr = dict_insert_stats_step(thr);
1912         } else if (type == QUE_NODE_ROW_PRINTF) {
1913                 thr = row_printf_step(thr);
1914         } else {
1915 --- a/storage/innobase/row/row0ins.c
1916 +++ b/storage/innobase/row/row0ins.c
1917 @@ -2018,6 +2018,8 @@
1918         }
1919  
1920  #ifdef UNIV_DEBUG
1921 +       if (!srv_use_sys_stats_table
1922 +           || index != UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes))
1923         {
1924                 page_t* page = btr_cur_get_page(&cursor);
1925                 rec_t*  first_rec = page_rec_get_next(
1926 --- a/storage/innobase/row/row0merge.c
1927 +++ b/storage/innobase/row/row0merge.c
1928 @@ -2019,6 +2019,8 @@
1929                 "UPDATE SYS_INDEXES SET NAME=CONCAT('"
1930                 TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
1931                 "COMMIT WORK;\n"
1932 +               /* Drop the statistics of the index. */
1933 +               "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
1934                 /* Drop the field definitions of the index. */
1935                 "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
1936                 /* Drop the index definition and the B-tree. */
1937 --- a/storage/innobase/row/row0mysql.c
1938 +++ b/storage/innobase/row/row0mysql.c
1939 @@ -922,6 +922,9 @@
1940  
1941         table->stat_modified_counter = counter + 1;
1942  
1943 +       if (!srv_stats_auto_update)
1944 +               return;
1945 +
1946         /* Calculate new statistics if 1 / 16 of table has been modified
1947         since the last time a statistics batch was run, or if
1948         stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
1949 @@ -932,7 +935,7 @@
1950             || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
1951  
1952                 dict_update_statistics(table, FALSE /* update even if stats
1953 -                                                   are initialized */);
1954 +                                                   are initialized */, TRUE);
1955         }
1956  }
1957  
1958 @@ -2077,6 +2080,71 @@
1959  }
1960  
1961  /*********************************************************************//**
1962 +*/
1963 +UNIV_INTERN
1964 +int
1965 +row_insert_stats_for_mysql(
1966 +/*=======================*/
1967 +       dict_index_t*   index,
1968 +       trx_t*          trx)
1969 +{
1970 +       ind_node_t*     node;
1971 +       mem_heap_t*     heap;
1972 +       que_thr_t*      thr;
1973 +       ulint           err;
1974 +
1975 +       //ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1976 +
1977 +       trx->op_info = "try to insert rows to SYS_STATS";
1978 +
1979 +       trx_start_if_not_started(trx);
1980 +       trx->error_state = DB_SUCCESS;
1981 +
1982 +       heap = mem_heap_create(512);
1983 +
1984 +       node = ind_insert_stats_graph_create(index, heap);
1985 +
1986 +       thr = pars_complete_graph_for_exec(node, trx, heap);
1987 +
1988 +       ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1989 +       que_run_threads(thr);
1990 +
1991 +       err = trx->error_state;
1992 +
1993 +       que_graph_free((que_t*) que_node_get_parent(thr));
1994 +
1995 +       trx->op_info = "";
1996 +
1997 +       return((int) err);
1998 +}
1999 +
2000 +/*********************************************************************//**
2001 +*/
2002 +UNIV_INTERN
2003 +int
2004 +row_delete_stats_for_mysql(
2005 +/*=============================*/
2006 +       dict_index_t*   index,
2007 +       trx_t*          trx)
2008 +{
2009 +       pars_info_t*    info    = pars_info_create();
2010 +
2011 +       trx->op_info = "delete rows from SYS_STATS";
2012 +
2013 +       trx_start_if_not_started(trx);
2014 +       trx->error_state = DB_SUCCESS;
2015 +
2016 +       pars_info_add_ull_literal(info, "indexid", index->id);
2017 +
2018 +       return((int) que_eval_sql(info,
2019 +                                 "PROCEDURE DELETE_STATISTICS_PROC () IS\n"
2020 +                                 "BEGIN\n"
2021 +                                 "DELETE FROM SYS_STATS WHERE INDEX_ID = :indexid;\n"
2022 +                                 "END;\n"
2023 +                                 , TRUE, trx));
2024 +}
2025 +
2026 +/*********************************************************************//**
2027  Scans a table create SQL string and adds to the data dictionary
2028  the foreign key constraints declared in the string. This function
2029  should be called after the indexes for a table have been created.
2030 @@ -3001,7 +3069,7 @@
2031         dict_table_autoinc_initialize(table, 1);
2032         dict_table_autoinc_unlock(table);
2033         dict_update_statistics(table, FALSE /* update even if stats are
2034 -                                           initialized */);
2035 +                                           initialized */, TRUE);
2036  
2037         trx_commit_for_mysql(trx);
2038  
2039 @@ -3312,6 +3380,8 @@
2040                            "       IF (SQL % NOTFOUND) THEN\n"
2041                            "               found := 0;\n"
2042                            "       ELSE\n"
2043 +                          "               DELETE FROM SYS_STATS\n"
2044 +                          "               WHERE INDEX_ID = index_id;\n"
2045                            "               DELETE FROM SYS_FIELDS\n"
2046                            "               WHERE INDEX_ID = index_id;\n"
2047                            "               DELETE FROM SYS_INDEXES\n"
2048 --- a/storage/innobase/row/row0row.c
2049 +++ b/storage/innobase/row/row0row.c
2050 @@ -364,6 +364,14 @@
2051  
2052         rec_len = rec_offs_n_fields(offsets);
2053  
2054 +       if (srv_use_sys_stats_table
2055 +           && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)) {
2056 +               if (rec_len < dict_index_get_n_fields(index)) {
2057 +                       /* the new record should be extended */
2058 +                       rec_len = dict_index_get_n_fields(index);
2059 +               }
2060 +       }
2061 +
2062         entry = dtuple_create(heap, rec_len);
2063  
2064         dtuple_set_n_fields_cmp(entry,
2065 @@ -375,6 +383,14 @@
2066         for (i = 0; i < rec_len; i++) {
2067  
2068                 dfield = dtuple_get_nth_field(entry, i);
2069 +
2070 +               if (srv_use_sys_stats_table
2071 +                   && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
2072 +                   && i >= rec_offs_n_fields(offsets)) {
2073 +                       dfield_set_null(dfield);
2074 +                       continue;
2075 +               }
2076 +
2077                 field = rec_get_nth_field(rec, offsets, i, &len);
2078  
2079                 dfield_set_data(dfield, field, len);
2080 --- a/storage/innobase/row/row0upd.c
2081 +++ b/storage/innobase/row/row0upd.c
2082 @@ -439,6 +439,12 @@
2083                                 0);
2084                 }
2085  
2086 +               if (srv_use_sys_stats_table
2087 +                   && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
2088 +                   && upd_field->field_no >= rec_offs_n_fields(offsets)) {
2089 +                       return(TRUE);
2090 +               }
2091 +
2092                 old_len = rec_offs_nth_size(offsets, upd_field->field_no);
2093  
2094                 if (rec_offs_comp(offsets)
2095 @@ -879,6 +885,18 @@
2096  
2097         for (i = 0; i < dtuple_get_n_fields(entry); i++) {
2098  
2099 +               if (srv_use_sys_stats_table
2100 +                   && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)
2101 +                   && i >= rec_offs_n_fields(offsets)) {
2102 +                       dfield = dtuple_get_nth_field(entry, i);
2103 +
2104 +                       upd_field = upd_get_nth_field(update, n_diff);
2105 +                       dfield_copy(&(upd_field->new_val), dfield);
2106 +                       upd_field_set_field_no(upd_field, i, index, trx);
2107 +                       n_diff++;
2108 +                       goto skip_compare;
2109 +               }
2110 +
2111                 data = rec_get_nth_field(rec, offsets, i, &len);
2112  
2113                 dfield = dtuple_get_nth_field(entry, i);
2114 --- a/storage/innobase/srv/srv0srv.c
2115 +++ b/storage/innobase/srv/srv0srv.c
2116 @@ -400,6 +400,9 @@
2117  /* When estimating number of different key values in an index, sample
2118  this many index pages */
2119  UNIV_INTERN unsigned long long srv_stats_sample_pages = 8;
2120 +UNIV_INTERN ulint      srv_stats_auto_update = 1;
2121 +UNIV_INTERN ulint      srv_stats_update_need_lock = 1;
2122 +UNIV_INTERN ibool      srv_use_sys_stats_table = FALSE;
2123  
2124  UNIV_INTERN ibool      srv_use_doublewrite_buf = TRUE;
2125  UNIV_INTERN ibool      srv_use_checksums = TRUE;
2126 --- a/storage/innobase/trx/trx0rec.c
2127 +++ b/storage/innobase/trx/trx0rec.c
2128 @@ -669,14 +669,27 @@
2129         /* Save to the undo log the old values of the columns to be updated. */
2130  
2131         if (update) {
2132 +               ulint   extended = 0;
2133 +
2134                 if (trx_undo_left(undo_page, ptr) < 5) {
2135  
2136                         return(0);
2137                 }
2138  
2139 -               ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
2140 +               if (srv_use_sys_stats_table
2141 +                   && index == UT_LIST_GET_FIRST(dict_sys->sys_stats->indexes)) {
2142 +                       for (i = 0; i < upd_get_n_fields(update); i++) {
2143 +                               ulint   pos = upd_get_nth_field(update, i)->field_no;
2144 +
2145 +                               if (pos >= rec_offs_n_fields(offsets)) {
2146 +                                       extended++;
2147 +                               }
2148 +                       }
2149 +               }
2150 +
2151 +               ptr += mach_write_compressed(ptr, upd_get_n_fields(update) - extended);
2152  
2153 -               for (i = 0; i < upd_get_n_fields(update); i++) {
2154 +               for (i = 0; i < upd_get_n_fields(update) - extended; i++) {
2155  
2156                         ulint   pos = upd_get_nth_field(update, i)->field_no;
2157  
2158 --- /dev/null
2159 +++ b/mysql-test/r/percona_innodb_use_sys_stats_table.result
2160 @@ -0,0 +1,3 @@
2161 +show variables like 'innodb_use_sys_stats%';
2162 +Variable_name  Value
2163 +innodb_use_sys_stats_table     ON
2164 --- /dev/null
2165 +++ b/mysql-test/t/percona_innodb_use_sys_stats_table-master.opt
2166 @@ -0,0 +1 @@
2167 +--innodb_use_sys_stats_table
2168 --- /dev/null
2169 +++ b/mysql-test/t/percona_innodb_use_sys_stats_table.test
2170 @@ -0,0 +1,2 @@
2171 +--source include/have_innodb.inc
2172 +show variables like 'innodb_use_sys_stats%';
This page took 0.185622 seconds and 3 git commands to generate.