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