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