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