]> git.pld-linux.org Git - packages/mysql.git/blame - mysql-userstats.patch
This commit was manufactured by cvs2git to create branch 'MYSQL_5_0'.
[packages/mysql.git] / mysql-userstats.patch
CommitLineData
9cb44948
AM
1diff -r ab66c8ca382a include/mysql_com.h
2--- a/include/mysql_com.h Thu Sep 04 12:08:00 2008 -0700
3+++ b/include/mysql_com.h Thu Sep 04 12:12:44 2008 -0700
4@@ -115,6 +115,8 @@
833f2639
ER
5 thread */
6 #define REFRESH_MASTER 128 /* Remove all bin logs in the index
7 and truncate the index */
8+#define REFRESH_TABLE_STATS 256 /* Refresh table stats hash table */
9+#define REFRESH_INDEX_STATS 512 /* Refresh index stats hash table */
10
11 /* The following can't be set with mysql_refresh() */
12 #define REFRESH_READ_LOCK 16384 /* Lock tables for read */
9cb44948 13diff -r ab66c8ca382a patch_info/userstats.info
833f2639 14--- /dev/null Thu Jan 01 00:00:00 1970 +0000
9cb44948 15+++ b/patch_info/userstats.info Thu Sep 04 12:12:44 2008 -0700
833f2639
ER
16@@ -0,0 +1,6 @@
17+File=userstats.patch
18+Name=SHOW USER/TABLE/INDEX statistics
19+Version=1.0
20+Author=Google
21+License=GPL
22+Comment=Added INFORMATION_SCHEMA.*_STATISTICS
9cb44948
AM
23diff -r ab66c8ca382a sql/handler.cc
24--- a/sql/handler.cc Thu Sep 04 12:08:00 2008 -0700
25+++ b/sql/handler.cc Thu Sep 04 12:12:44 2008 -0700
26@@ -1168,6 +1168,7 @@
833f2639
ER
27 error=1;
28 }
9cb44948 29 status_var_increment(thd->status_var.ha_commit_count);
833f2639 30+ thd->diff_commit_trans++;
9cb44948
AM
31 ha_info_next= ha_info->next();
32 ha_info->reset(); /* keep it conveniently zero-filled */
833f2639 33 }
9cb44948 34@@ -1235,6 +1236,7 @@
833f2639
ER
35 error=1;
36 }
9cb44948 37 status_var_increment(thd->status_var.ha_rollback_count);
833f2639 38+ thd->diff_rollback_trans++;
9cb44948
AM
39 ha_info_next= ha_info->next();
40 ha_info->reset(); /* keep it conveniently zero-filled */
833f2639 41 }
9cb44948 42@@ -1682,6 +1684,7 @@
833f2639
ER
43 error=1;
44 }
9cb44948 45 status_var_increment(thd->status_var.ha_rollback_count);
833f2639 46+ thd->diff_rollback_trans++;
9cb44948
AM
47 ha_info_next= ha_info->next();
48 ha_info->reset(); /* keep it conveniently zero-filled */
833f2639 49 }
9cb44948
AM
50@@ -2016,6 +2019,8 @@
51 dup_ref=ref+ALIGN_SIZE(ref_length);
52 cached_table_flags= table_flags();
833f2639
ER
53 }
54+ rows_read = rows_changed = 0;
55+ memset(index_rows_read, 0, sizeof(index_rows_read));
56 DBUG_RETURN(error);
57 }
58
9cb44948
AM
59@@ -3448,6 +3453,97 @@
60 return;
833f2639
ER
61 }
62
63+// Updates the global table stats with the TABLE this handler represents.
64+void handler::update_global_table_stats() {
65+ if (!rows_read && !rows_changed) return; // Nothing to update.
66+ // table_cache_key is db_name + '\0' + table_name + '\0'.
9cb44948 67+ if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str) return;
833f2639
ER
68+
69+ TABLE_STATS* table_stats;
70+ char key[NAME_LEN * 2 + 2];
71+ // [db] + '.' + [table]
9cb44948 72+ sprintf(key, "%s.%s", table->s->table_cache_key.str, table->s->table_name.str);
833f2639
ER
73+
74+ pthread_mutex_lock(&LOCK_global_table_stats);
75+ // Gets the global table stats, creating one if necessary.
76+ if (!(table_stats = (TABLE_STATS*)hash_search(&global_table_stats,
9cb44948 77+ (uchar*)key,
833f2639
ER
78+ strlen(key)))) {
79+ if (!(table_stats = ((TABLE_STATS*)
80+ my_malloc(sizeof(TABLE_STATS), MYF(MY_WME))))) {
81+ // Out of memory.
82+ sql_print_error("Allocating table stats failed.");
83+ goto end;
84+ }
85+ strncpy(table_stats->table, key, sizeof(table_stats->table));
86+ table_stats->rows_read = 0;
87+ table_stats->rows_changed = 0;
88+ table_stats->rows_changed_x_indexes = 0;
89+
9cb44948 90+ if (my_hash_insert(&global_table_stats, (uchar*)table_stats)) {
833f2639
ER
91+ // Out of memory.
92+ sql_print_error("Inserting table stats failed.");
93+ my_free((char*)table_stats, 0);
94+ goto end;
95+ }
96+ }
97+ // Updates the global table stats.
98+ table_stats->rows_read += rows_read;
99+ table_stats->rows_changed += rows_changed;
100+ table_stats->rows_changed_x_indexes +=
101+ rows_changed * (table->s->keys ? table->s->keys : 1);
102+ rows_read = rows_changed = 0;
103+end:
104+ pthread_mutex_unlock(&LOCK_global_table_stats);
105+}
106+
107+// Updates the global index stats with this handler's accumulated index reads.
108+void handler::update_global_index_stats() {
109+ // table_cache_key is db_name + '\0' + table_name + '\0'.
9cb44948 110+ if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str) return;
833f2639
ER
111+
112+ for (int x = 0; x < table->s->keys; x++) {
113+ if (index_rows_read[x]) {
114+ // Rows were read using this index.
115+ KEY* key_info = &table->key_info[x];
116+
117+ if (!key_info->name) continue;
118+
119+ INDEX_STATS* index_stats;
120+ char key[NAME_LEN * 3 + 3];
121+ // [db] + '.' + [table] + '.' + [index]
9cb44948
AM
122+ sprintf(key, "%s.%s.%s", table->s->table_cache_key.str,
123+ table->s->table_name.str, key_info->name);
833f2639
ER
124+
125+ pthread_mutex_lock(&LOCK_global_index_stats);
126+ // Gets the global index stats, creating one if necessary.
127+ if (!(index_stats = (INDEX_STATS*)hash_search(&global_index_stats,
9cb44948 128+ (uchar*)key,
833f2639
ER
129+ strlen(key)))) {
130+ if (!(index_stats = ((INDEX_STATS*)
131+ my_malloc(sizeof(INDEX_STATS), MYF(MY_WME))))) {
132+ // Out of memory.
133+ sql_print_error("Allocating index stats failed.");
134+ goto end;
135+ }
136+ strncpy(index_stats->index, key, sizeof(index_stats->index));
137+ index_stats->rows_read = 0;
138+
9cb44948 139+ if (my_hash_insert(&global_index_stats, (uchar*)index_stats)) {
833f2639
ER
140+ // Out of memory.
141+ sql_print_error("Inserting index stats failed.");
142+ my_free((char*)index_stats, 0);
143+ goto end;
144+ }
145+ }
146+ // Updates the global index stats.
147+ index_stats->rows_read += index_rows_read[x];
148+ index_rows_read[x] = 0;
149+end:
150+ pthread_mutex_unlock(&LOCK_global_index_stats);
151+ }
152+ }
153+}
154
155 /****************************************************************************
156 ** Some general functions that isn't in the handler class
9cb44948
AM
157diff -r ab66c8ca382a sql/handler.h
158--- a/sql/handler.h Thu Sep 04 12:08:00 2008 -0700
159+++ b/sql/handler.h Thu Sep 04 12:12:44 2008 -0700
160@@ -29,6 +29,10 @@
161 #endif
162
833f2639 163 #define USING_TRANSACTIONS
833f2639
ER
164+
165+#if MAX_KEY > 128
166+#error MAX_KEY is too large. Values up to 128 are supported.
9cb44948 167+#endif
833f2639
ER
168
169 // the following is for checking tables
9cb44948
AM
170
171@@ -690,6 +694,7 @@
172 */
173 enum log_status (*get_log_status)(handlerton *hton, char *log);
174
175+
176 /*
177 Iterators creator.
178 Presence of the pointer should be checked before using
179@@ -1130,6 +1135,10 @@
180 */
181 Discrete_interval auto_inc_interval_for_cur_row;
182
183+ ulonglong rows_read;
184+ ulonglong rows_changed;
185+ ulonglong index_rows_read[MAX_KEY];
186+
187 handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
188 :table_share(share_arg), table(0),
189 estimation_rows_to_insert(0), ht(ht_arg),
190@@ -1154,8 +1154,10 @@
191 ft_handler(0), inited(NONE),
833f2639 192 locked(FALSE), implicit_emptied(0),
9cb44948
AM
193 pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0),
194- auto_inc_intervals_count(0)
833f2639 195- {}
9cb44948 196+ auto_inc_intervals_count(0), rows_read(0), rows_changed(0)
833f2639
ER
197+ {
198+ memset(index_rows_read, 0, sizeof(index_rows_read));
199+ }
9cb44948
AM
200 virtual ~handler(void)
201 {
202 DBUG_ASSERT(locked == FALSE);
203@@ -1262,7 +1273,13 @@
204 {
205 table= table_arg;
206 table_share= share;
833f2639
ER
207+ rows_read = rows_changed = 0;
208+ memset(index_rows_read, 0, sizeof(index_rows_read));
9cb44948
AM
209 }
210+
833f2639
ER
211+ void update_global_table_stats();
212+ void update_global_index_stats();
213+
9cb44948
AM
214 virtual double scan_time()
215 { return ulonglong2double(stats.data_file_length) / IO_SIZE + 2; }
216 virtual double read_time(uint index, uint ranges, ha_rows rows)
217diff -r ab66c8ca382a sql/lex.h
218--- a/sql/lex.h Thu Sep 04 12:08:00 2008 -0700
219+++ b/sql/lex.h Thu Sep 04 12:12:44 2008 -0700
220@@ -245,6 +245,7 @@
833f2639
ER
221 { "IN", SYM(IN_SYM)},
222 { "INDEX", SYM(INDEX_SYM)},
223 { "INDEXES", SYM(INDEXES)},
224+ { "INDEX_STATISTICS", SYM(INDEX_STATS_SYM)},
225 { "INFILE", SYM(INFILE)},
9cb44948 226 { "INITIAL_SIZE", SYM(INITIAL_SIZE_SYM)},
833f2639 227 { "INNER", SYM(INNER_SYM)},
9cb44948 228@@ -528,6 +529,7 @@
833f2639 229 { "TABLES", SYM(TABLES)},
9cb44948
AM
230 { "TABLESPACE", SYM(TABLESPACE)},
231 { "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)},
833f2639
ER
232+ { "TABLE_STATISTICS", SYM(TABLE_STATS_SYM)},
233 { "TEMPORARY", SYM(TEMPORARY)},
234 { "TEMPTABLE", SYM(TEMPTABLE_SYM)},
235 { "TERMINATED", SYM(TERMINATED)},
9cb44948 236@@ -570,6 +572,7 @@
833f2639
ER
237 { "USE", SYM(USE_SYM)},
238 { "USER", SYM(USER)},
239 { "USER_RESOURCES", SYM(RESOURCES)},
240+ { "USER_STATISTICS", SYM(USER_STATS_SYM)},
241 { "USE_FRM", SYM(USE_FRM)},
242 { "USING", SYM(USING)},
243 { "UTC_DATE", SYM(UTC_DATE_SYM)},
9cb44948
AM
244diff -r ab66c8ca382a sql/mysql_priv.h
245--- a/sql/mysql_priv.h Thu Sep 04 12:08:00 2008 -0700
246+++ b/sql/mysql_priv.h Thu Sep 04 12:12:44 2008 -0700
247@@ -1058,7 +1058,19 @@
833f2639
ER
248 bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
249 void init_max_user_conn(void);
250 void init_update_queries(void);
251+void init_global_user_stats(void);
252+void init_global_table_stats(void);
253+void init_global_index_stats(void);
254 void free_max_user_conn(void);
255+void free_global_user_stats(void);
256+void free_global_table_stats(void);
257+void free_global_index_stats(void);
9cb44948
AM
258+// Uses the THD to update the global stats.
259+void update_global_user_stats(THD* thd);
833f2639
ER
260+// Set stats for concurrent connections displayed by mysqld_show().
261+void set_concurrent_connections_stats();
9cb44948
AM
262+// Increments connection count for user.
263+int increment_connection_count(THD* thd, bool use_lock);
833f2639 264 pthread_handler_t handle_bootstrap(void *arg);
9cb44948
AM
265 int mysql_execute_command(THD *thd);
266 bool do_command(THD *thd);
267@@ -2009,6 +2021,12 @@
833f2639
ER
268 extern struct system_variables max_system_variables;
269 extern struct system_status_var global_status_var;
270 extern struct rand_struct sql_rand;
271+extern HASH global_user_stats;
272+extern pthread_mutex_t LOCK_global_user_stats;
273+extern HASH global_table_stats;
274+extern pthread_mutex_t LOCK_global_table_stats;
275+extern HASH global_index_stats;
276+extern pthread_mutex_t LOCK_global_index_stats;
277
278 extern const char *opt_date_time_formats[];
279 extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
9cb44948
AM
280diff -r ab66c8ca382a sql/mysqld.cc
281--- a/sql/mysqld.cc Thu Sep 04 12:08:00 2008 -0700
282+++ b/sql/mysqld.cc Thu Sep 04 12:12:44 2008 -0700
283@@ -588,6 +588,11 @@
833f2639 284 LOCK_global_system_variables,
9cb44948
AM
285 LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
286 LOCK_connection_count;
287+
833f2639
ER
288+pthread_mutex_t LOCK_global_user_stats;
289+pthread_mutex_t LOCK_global_table_stats;
290+pthread_mutex_t LOCK_global_index_stats;
9cb44948
AM
291+
292 /**
833f2639
ER
293 The below lock protects access to two global server variables:
294 max_prepared_stmt_count and prepared_stmt_count. These variables
9cb44948 295@@ -1265,6 +1270,9 @@
833f2639
ER
296 x_free(opt_secure_file_priv);
297 bitmap_free(&temp_pool);
298 free_max_user_conn();
299+ free_global_user_stats();
300+ free_global_table_stats();
301+ free_global_index_stats();
302 #ifdef HAVE_REPLICATION
303 end_slave_list();
9cb44948
AM
304 #endif
305@@ -1377,6 +1385,9 @@
833f2639
ER
306 (void) pthread_cond_destroy(&COND_thread_cache);
307 (void) pthread_cond_destroy(&COND_flush_thread_cache);
308 (void) pthread_cond_destroy(&COND_manager);
309+ (void) pthread_mutex_destroy(&LOCK_global_user_stats);
310+ (void) pthread_mutex_destroy(&LOCK_global_table_stats);
311+ (void) pthread_mutex_destroy(&LOCK_global_index_stats);
312 }
313
314 #endif /*EMBEDDED_LIBRARY*/
9cb44948
AM
315@@ -3069,6 +3080,7 @@
316 {"show_function_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS_FUNC]), SHOW_LONG_STATUS},
317 {"show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS},
318 {"show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS},
319+ {"show_index_stats", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_INDEX_STATS]), SHOW_LONG_STATUS},
320 {"show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS},
321 {"show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS},
322 {"show_open_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_OPEN_TABLES]), SHOW_LONG_STATUS},
323@@ -3085,9 +3097,11 @@
324 {"show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS},
325 {"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
326 {"show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
327+ {"show_table_stats", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATS]), SHOW_LONG_STATUS},
328 {"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS},
329 {"show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
330 {"show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS},
331+ {"show_user_stats", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_USER_STATS]), SHOW_LONG_STATUS},
332 {"show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
333 {"show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
334 {"slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
335@@ -3503,6 +3517,9 @@
833f2639 336 #endif
9cb44948
AM
337 (void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
338 (void) pthread_cond_init(&COND_server_started,NULL);
833f2639
ER
339+ (void) pthread_mutex_init(&LOCK_global_user_stats, MY_MUTEX_INIT_FAST);
340+ (void) pthread_mutex_init(&LOCK_global_table_stats, MY_MUTEX_INIT_FAST);
341+ (void) pthread_mutex_init(&LOCK_global_index_stats, MY_MUTEX_INIT_FAST);
342 sp_cache_init();
9cb44948
AM
343 #ifdef HAVE_EVENT_SCHEDULER
344 Events::init_mutexes();
345@@ -3872,6 +3889,9 @@
346 if (!errmesg[0][0])
833f2639 347 unireg_abort(1);
9cb44948
AM
348
349+ init_global_table_stats();
350+ init_global_index_stats();
833f2639 351+
9cb44948 352 /* We have to initialize the storage engines before CSV logging */
833f2639
ER
353 if (ha_init())
354 {
9cb44948 355@@ -4018,6 +4038,7 @@
833f2639
ER
356
357 init_max_user_conn();
358 init_update_queries();
359+ init_global_user_stats();
360 DBUG_RETURN(0);
361 }
362
9cb44948
AM
363diff -r ab66c8ca382a sql/sql_base.cc
364--- a/sql/sql_base.cc Thu Sep 04 12:08:00 2008 -0700
365+++ b/sql/sql_base.cc Thu Sep 04 12:12:44 2008 -0700
366@@ -1342,6 +1342,12 @@
833f2639 367 DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
9cb44948
AM
368 DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
369 table->s->table_name.str, (long) table));
370+
833f2639
ER
371+ if(table->file)
372+ {
373+ table->file->update_global_table_stats();
374+ table->file->update_global_index_stats();
375+ }
9cb44948 376
833f2639 377 *table_ptr=table->next;
9cb44948
AM
378 /*
379@@ -1880,6 +1886,9 @@
833f2639 380 DBUG_ENTER("close_temporary");
9cb44948
AM
381 DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
382 table->s->db.str, table->s->table_name.str));
383+
833f2639
ER
384+ table->file->update_global_table_stats();
385+ table->file->update_global_index_stats();
9cb44948 386
833f2639 387 free_io_cache(table);
9cb44948
AM
388 closefrm(table, 0);
389diff -r ab66c8ca382a sql/sql_class.cc
390--- a/sql/sql_class.cc Thu Sep 04 12:08:00 2008 -0700
391+++ b/sql/sql_class.cc Thu Sep 04 12:12:44 2008 -0700
392@@ -577,6 +577,8 @@
833f2639
ER
393 bzero(ha_data, sizeof(ha_data));
394 mysys_var=0;
395 binlog_evt_union.do_union= FALSE;
396+ busy_time = 0;
397+ updated_row_count = 0;
9cb44948 398 enable_slow_log= 0;
833f2639
ER
399 #ifndef DBUG_OFF
400 dbug_sentry=THD_SENTRY_MAGIC;
9cb44948 401@@ -761,8 +763,55 @@
833f2639 402 update_charset();
9cb44948 403 reset_current_stmt_binlog_row_based();
833f2639
ER
404 bzero((char *) &status_var, sizeof(status_var));
405+ reset_stats();
406 }
407
408+// Resets stats in a THD.
409+void THD::reset_stats(void) {
410+ current_connect_time = time(NULL);
411+ last_global_update_time = current_connect_time;
412+ reset_diff_stats();
413+}
414+
415+// Resets the 'diff' stats, which are used to update global stats.
416+void THD::reset_diff_stats(void) {
417+ diff_total_busy_time = 0;
418+ diff_total_sent_rows = 0;
419+ diff_total_updated_rows = 0;
420+ diff_select_commands = 0;
421+ diff_update_commands = 0;
422+ diff_other_commands = 0;
423+ diff_commit_trans = 0;
424+ diff_rollback_trans = 0;
425+}
426+
427+// Updates 'diff' stats of a THD.
428+void THD::update_stats() {
429+ diff_total_busy_time += busy_time;
430+ diff_total_sent_rows += sent_row_count;
431+ diff_total_updated_rows += updated_row_count;
432+ // The replication thread has the COM_CONNECT command.
433+ if ((old_command == COM_QUERY || command == COM_CONNECT) &&
434+ (lex->sql_command >= 0 && lex->sql_command < SQLCOM_END)) {
435+ // A SQL query.
436+ if (lex->sql_command == SQLCOM_SELECT) {
9cb44948 437+ if (!(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND)) {
833f2639
ER
438+ diff_select_commands++;
439+ } else {
440+ // 'SHOW ' commands become SQLCOM_SELECT.
441+ diff_other_commands++;
442+ // 'SHOW ' commands shouldn't inflate total sent row count.
443+ diff_total_sent_rows -= sent_row_count;
444+ }
445+ } else if (is_update_query(lex->sql_command)) {
446+ diff_update_commands++;
447+ } else {
448+ diff_other_commands++;
449+ }
450+ }
451+ // diff_commit_trans is updated in handler.cc.
452+ // diff_rollback_trans is updated in handler.cc.
453+}
454
455 /*
456 Init THD for query processing.
9cb44948
AM
457diff -r ab66c8ca382a sql/sql_class.h
458--- a/sql/sql_class.h Thu Sep 04 12:08:00 2008 -0700
459+++ b/sql/sql_class.h Thu Sep 04 12:12:44 2008 -0700
460@@ -1310,6 +1310,8 @@
833f2639
ER
461 first byte of the packet in do_command()
462 */
463 enum enum_server_command command;
464+ // Used to save the command, before it is set to COM_SLEEP.
465+ enum enum_server_command old_command;
466 uint32 server_id;
467 uint32 file_id; // for LOAD DATA INFILE
9cb44948
AM
468 /* remote (peer) port */
469@@ -1584,6 +1586,7 @@
833f2639
ER
470 ulonglong options; /* Bitmap of states */
471 longlong row_count_func; /* For the ROW_COUNT() function */
472 ha_rows cuted_fields;
473+ ha_rows updated_row_count;
474
475 /*
476 number of rows we actually sent to the client, including "synthetic"
9cb44948 477@@ -1735,6 +1738,27 @@
833f2639
ER
478 */
479 LOG_INFO* current_linfo;
480 NET* slave_net; // network connection from slave -> m.
481+
482+ /*
483+ Used to update global user stats. The global user stats are updated
484+ occasionally with the 'diff' variables. After the update, the 'diff'
485+ variables are reset to 0.
486+ */
487+ // Time when the current thread connected to MySQL.
488+ time_t current_connect_time;
489+ // Last time when THD stats were updated in global_user_stats.
490+ time_t last_global_update_time;
491+ // Busy (non-idle) time for just one command.
492+ double busy_time;
493+ // Busy time not updated in global_user_stats yet.
494+ double diff_total_busy_time;
495+ // Number of rows not reflected in global_user_stats yet.
496+ ha_rows diff_total_sent_rows, diff_total_updated_rows;
497+ // Number of commands not reflected in global_user_stats yet.
498+ ulonglong diff_select_commands, diff_update_commands, diff_other_commands;
499+ // Number of transactions not reflected in global_user_stats yet.
500+ ulonglong diff_commit_trans, diff_rollback_trans;
501+
502 /* Used by the sys_var class to store temporary values */
503 union
504 {
9cb44948
AM
505@@ -1797,6 +1821,9 @@
506 alloc_root.
833f2639
ER
507 */
508 void init_for_queries();
509+ void reset_stats(void);
510+ void reset_diff_stats(void);
511+ void update_stats(void);
512 void change_user(void);
513 void cleanup(void);
514 void cleanup_after_query();
9cb44948
AM
515diff -r ab66c8ca382a sql/sql_connect.cc
516--- a/sql/sql_connect.cc Thu Sep 04 12:08:00 2008 -0700
517+++ b/sql/sql_connect.cc Thu Sep 04 12:12:44 2008 -0700
518@@ -520,6 +520,14 @@
519 0,0,
520 (hash_get_key) get_key_conn, (hash_free_key) free_user,
521 0);
522+ if (hash_init(&hash_user_connections,system_charset_info,max_connections,
523+ 0,0,
524+ (hash_get_key) get_key_conn, (hash_free_key) free_user,
525+ 0)) {
526+ sql_print_error("Initializing hash_user_connections failed.");
527+ exit(1);
528+ }
529+
530 #endif
531 }
532
533@@ -1107,6 +1115,13 @@
534 if (login_connection(thd))
535 goto end_thread;
536
537+ thd->reset_stats();
538+ // Updates global user connection stats.
539+ if (increment_connection_count(thd, true)) {
540+ net_send_error(thd, ER_OUTOFMEMORY); // Out of memory
541+ goto end_thread;
542+ }
543+
544 prepare_new_connection_state(thd);
545
546 while (!net->error && net->vio != 0 &&
547@@ -1119,6 +1134,8 @@
548
549 end_thread:
550 close_connection(thd, 0, 1);
551+ thd->update_stats();
552+ update_global_user_stats(thd);
553 if (thread_scheduler.end_thread(thd,1))
554 return 0; // Probably no-threads
555
556diff -r ab66c8ca382a sql/sql_delete.cc
557--- a/sql/sql_delete.cc Thu Sep 04 12:08:00 2008 -0700
558+++ b/sql/sql_delete.cc Thu Sep 04 12:12:44 2008 -0700
559@@ -402,6 +402,7 @@
560 my_ok(thd, (ha_rows) thd->row_count_func);
833f2639
ER
561 DBUG_PRINT("info",("%ld records deleted",(long) deleted));
562 }
563+ thd->updated_row_count += deleted;
9cb44948 564 DBUG_RETURN(error >= 0 || thd->is_error());
833f2639
ER
565 }
566
9cb44948 567@@ -938,6 +939,7 @@
833f2639 568 thd->row_count_func= deleted;
9cb44948 569 ::my_ok(thd, (ha_rows) thd->row_count_func);
833f2639
ER
570 }
571+ thd->updated_row_count += deleted;
572 return 0;
573 }
574
9cb44948
AM
575diff -r ab66c8ca382a sql/sql_insert.cc
576--- a/sql/sql_insert.cc Thu Sep 04 12:08:00 2008 -0700
577+++ b/sql/sql_insert.cc Thu Sep 04 12:12:44 2008 -0700
578@@ -969,6 +969,7 @@
833f2639 579 thd->row_count_func= info.copied + info.deleted + updated;
9cb44948 580 ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
833f2639
ER
581 }
582+ thd->updated_row_count += thd->row_count_func;
583 thd->abort_on_warning= 0;
584 DBUG_RETURN(FALSE);
585
9cb44948
AM
586diff -r ab66c8ca382a sql/sql_lex.h
587--- a/sql/sql_lex.h Thu Sep 04 12:08:00 2008 -0700
588+++ b/sql/sql_lex.h Thu Sep 04 12:12:44 2008 -0700
589@@ -118,7 +118,7 @@
590 SQLCOM_SHOW_CREATE_TRIGGER,
591 SQLCOM_ALTER_DB_UPGRADE,
592 SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
593-
594+ SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS,
595 /*
596 When a command is added here, be sure it's also added in mysqld.cc
597 in "struct show_var_st status_vars[]= {" ...
598diff -r ab66c8ca382a sql/sql_parse.cc
599--- a/sql/sql_parse.cc Thu Sep 04 12:08:00 2008 -0700
600+++ b/sql/sql_parse.cc Thu Sep 04 12:12:44 2008 -0700
601@@ -45,6 +45,15 @@
602
603 static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
833f2639 604 static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
833f2639
ER
605+
606+HASH global_user_stats;
607+extern pthread_mutex_t LOCK_global_user_stats;
608+
609+HASH global_table_stats;
610+extern pthread_mutex_t LOCK_global_table_stats;
611+
612+HASH global_index_stats;
613+extern pthread_mutex_t LOCK_global_index_stats;
614
9cb44948
AM
615 const char *any_db="*any*"; // Special symbol for check_access
616
617@@ -278,7 +287,9 @@
618 sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND;
619 sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
620 sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND;
621- sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
622+ sql_command_flags[SQLCOM_SHOW_USER_STATS]= CF_STATUS_COMMAND;
623+ sql_command_flags[SQLCOM_SHOW_TABLE_STATS]= CF_STATUS_COMMAND;
624+ sql_command_flags[SQLCOM_SHOW_INDEX_STATS]= CF_STATUS_COMMAND;
625
626 sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND |
627 CF_SHOW_TABLE_COMMAND |
628@@ -481,6 +492,86 @@
629 DBUG_RETURN(0);
630 }
631
632+extern "C" uchar *get_key_user_stats(USER_STATS *user_stats, size_t *length,
833f2639
ER
633+ my_bool not_used __attribute__((unused)))
634+{
635+ *length = strlen(user_stats->user);
9cb44948 636+ return (uchar*)user_stats->user;
833f2639
ER
637+}
638+
639+extern "C" void free_user_stats(USER_STATS* user_stats)
640+{
641+ my_free((char*)user_stats, MYF(0));
642+}
643+
644+void init_global_user_stats(void)
645+{
646+ if (hash_init(&global_user_stats, system_charset_info, max_connections,
647+ 0, 0, (hash_get_key)get_key_user_stats,
648+ (hash_free_key)free_user_stats, 0)) {
649+ sql_print_error("Initializing global_user_stats failed.");
650+ exit(1);
651+ }
652+}
653+
9cb44948 654+extern "C" uchar *get_key_table_stats(TABLE_STATS *table_stats, size_t *length,
833f2639
ER
655+ my_bool not_used __attribute__((unused)))
656+{
657+ *length = strlen(table_stats->table);
9cb44948 658+ return (uchar*)table_stats->table;
833f2639
ER
659+}
660+
661+extern "C" void free_table_stats(TABLE_STATS* table_stats)
662+{
663+ my_free((char*)table_stats, MYF(0));
664+}
665+
666+void init_global_table_stats(void)
667+{
668+ if (hash_init(&global_table_stats, system_charset_info, max_connections,
669+ 0, 0, (hash_get_key)get_key_table_stats,
670+ (hash_free_key)free_table_stats, 0)) {
671+ sql_print_error("Initializing global_table_stats failed.");
672+ exit(1);
673+ }
674+}
675+
9cb44948 676+extern "C" uchar *get_key_index_stats(INDEX_STATS *index_stats, size_t *length,
833f2639
ER
677+ my_bool not_used __attribute__((unused)))
678+{
679+ *length = strlen(index_stats->index);
9cb44948 680+ return (uchar*)index_stats->index;
833f2639
ER
681+}
682+
683+extern "C" void free_index_stats(INDEX_STATS* index_stats)
684+{
685+ my_free((char*)index_stats, MYF(0));
686+}
687+
688+void init_global_index_stats(void)
689+{
690+ if (hash_init(&global_index_stats, system_charset_info, max_connections,
691+ 0, 0, (hash_get_key)get_key_index_stats,
692+ (hash_free_key)free_index_stats, 0)) {
693+ sql_print_error("Initializing global_index_stats failed.");
694+ exit(1);
695+ }
696+}
9cb44948 697+
833f2639
ER
698+void free_global_user_stats(void)
699+{
700+ hash_free(&global_user_stats);
701+}
702+
703+void free_global_table_stats(void)
704+{
705+ hash_free(&global_table_stats);
706+}
707+
708+void free_global_index_stats(void)
709+{
710+ hash_free(&global_index_stats);
711+}
712
9cb44948
AM
713 /**
714 @brief Check access privs for a MERGE table and fix children lock types.
715@@ -899,6 +990,9 @@
716 DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
717
718 thd->command=command;
719+ // To increment the correct command counter for user stats, 'command' must
720+ // be saved because it is set to COM_SLEEP at the end of this function.
721+ thd->old_command = command;
722 /*
723 Commands which always take a long time are logged into
724 the slow log only if opt_log_slow_admin_statements is set.
725@@ -1677,6 +1771,9 @@
726 case SCH_COLUMN_PRIVILEGES:
727 case SCH_TABLE_CONSTRAINTS:
728 case SCH_KEY_COLUMN_USAGE:
729+ case SCH_USER_STATS:
730+ case SCH_TABLE_STATS:
731+ case SCH_INDEX_STATS:
732 default:
733 break;
734 }
735@@ -2020,6 +2117,9 @@
736 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server");
737 break;
738 #endif
739+ case SQLCOM_SHOW_USER_STATS:
740+ case SQLCOM_SHOW_TABLE_STATS:
741+ case SQLCOM_SHOW_INDEX_STATS:
742 case SQLCOM_SHOW_STATUS_PROC:
743 case SQLCOM_SHOW_STATUS_FUNC:
744 res= execute_sqlcom_select(thd, all_tables);
745@@ -2195,6 +2295,7 @@
746 }
747 #endif
748
749+
750 case SQLCOM_BACKUP_TABLE:
751 {
752 DBUG_ASSERT(first_table == all_tables && first_table != 0);
753@@ -5245,6 +5346,130 @@
754 #endif /*NO_EMBEDDED_ACCESS_CHECKS*/
833f2639 755
833f2639
ER
756
757+// 'mysql_system_user' is used for when the user is not defined for a THD.
758+static char mysql_system_user[] = "#mysql_system#";
759+
760+// Returns 'user' if it's not NULL. Returns 'mysql_system_user' otherwise.
761+static char* get_valid_user_string(char* user) {
762+ return user ? user : mysql_system_user;
763+}
764+
765+// Increments the global user stats connection count. If 'use_lock' is true,
766+// 'LOCK_global_user_stats' will be locked/unlocked. Returns 0 on success,
767+// 1 on error.
9cb44948 768+int increment_connection_count(THD* thd, bool use_lock) {
833f2639
ER
769+ char* user_string = get_valid_user_string(thd->main_security_ctx.user);
770+
771+ USER_STATS* user_stats;
772+ int return_value = 0;
773+
774+ if (use_lock) pthread_mutex_lock(&LOCK_global_user_stats);
775+ if (!(user_stats = (USER_STATS*)hash_search(&global_user_stats,
9cb44948 776+ (uchar*)user_string,
833f2639
ER
777+ strlen(user_string)))) {
778+ // First connection for this user.
779+ if (!(user_stats = ((USER_STATS*)
780+ my_malloc(sizeof(USER_STATS), MYF(MY_WME))))) {
781+ // Out of memory.
782+ return_value = 1;
783+ goto end;
784+ }
785+ strncpy(user_stats->user, user_string, sizeof(user_stats->user));
786+ user_stats->total_connections = 0;
787+ user_stats->concurrent_connections = 0;
788+ user_stats->connected_time = 0;
789+ user_stats->busy_time = 0;
790+ user_stats->rows_fetched = 0;
791+ user_stats->rows_updated = 0;
792+ user_stats->select_commands = 0;
793+ user_stats->update_commands = 0;
794+ user_stats->other_commands = 0;
795+ user_stats->commit_trans = 0;
796+ user_stats->rollback_trans = 0;
797+
9cb44948 798+ if (my_hash_insert(&global_user_stats, (uchar*)user_stats)) {
833f2639
ER
799+ // Out of memory.
800+ my_free((char*)user_stats, 0);
801+ return_value = 1;
802+ goto end;
803+ }
804+ }
805+ user_stats->total_connections++;
806+end:
807+ if (use_lock) pthread_mutex_unlock(&LOCK_global_user_stats);
808+ return return_value;
809+}
810+
811+// Used to update the global user stats.
812+static void update_global_user_stats_with_user(THD* thd,
813+ USER_STATS* user_stats) {
814+ time_t current_time = time(NULL);
815+ user_stats->connected_time += current_time - thd->last_global_update_time;
816+ thd->last_global_update_time = current_time;
817+ user_stats->busy_time += thd->diff_total_busy_time;
818+ user_stats->rows_fetched += thd->diff_total_sent_rows;
819+ user_stats->rows_updated += thd->diff_total_updated_rows;
820+ user_stats->select_commands += thd->diff_select_commands;
821+ user_stats->update_commands += thd->diff_update_commands;
822+ user_stats->other_commands += thd->diff_other_commands;
823+ user_stats->commit_trans += thd->diff_commit_trans;
824+ user_stats->rollback_trans += thd->diff_rollback_trans;
825+}
826+
827+// Updates the global stats of a thread/user.
9cb44948 828+void update_global_user_stats(THD* thd) {
833f2639
ER
829+ char* user_string = get_valid_user_string(thd->main_security_ctx.user);
830+
831+ USER_STATS* user_stats;
832+ pthread_mutex_lock(&LOCK_global_user_stats);
833+ if ((user_stats = (USER_STATS*)hash_search(&global_user_stats,
9cb44948 834+ (uchar*)user_string,
833f2639
ER
835+ strlen(user_string)))) {
836+ // Found user.
837+ update_global_user_stats_with_user(thd, user_stats);
838+ thd->reset_diff_stats();
839+ } else {
840+ // The user name should exist.
841+ increment_connection_count(thd, false);
842+ }
843+ pthread_mutex_unlock(&LOCK_global_user_stats);
844+}
845+
846+// Determines the concurrent number of connections of current threads.
847+void set_concurrent_connections_stats() {
848+ USER_STATS* user_stats;
849+
850+ pthread_mutex_lock(&LOCK_global_user_stats);
851+ pthread_mutex_lock(&LOCK_thread_count);
852+
853+ // Resets all concurrent connections to 0.
854+ for (int i = 0; i < global_user_stats.records; ++i) {
855+ user_stats = (USER_STATS*)hash_element(&global_user_stats, i);
856+ user_stats->concurrent_connections = 0;
857+ }
858+
859+ I_List_iterator<THD> it(threads);
860+ THD* thd;
861+ // Iterates through the current threads.
862+ while ((thd = it++)) {
863+ char* user_string = get_valid_user_string(thd->main_security_ctx.user);
864+ if ((user_stats = (USER_STATS*)hash_search(&global_user_stats,
9cb44948 865+ (uchar*)user_string,
833f2639
ER
866+ strlen(user_string)))) {
867+ // Found user.
868+ user_stats->concurrent_connections++;
869+ update_global_user_stats_with_user(thd, user_stats);
870+ thd->reset_diff_stats();
871+ } else {
872+ // The user name should exist.
873+ increment_connection_count(thd, false);
874+ }
875+ }
876+ pthread_mutex_unlock(&LOCK_thread_count);
877+ pthread_mutex_unlock(&LOCK_global_user_stats);
878+}
879+
833f2639 880+
9cb44948
AM
881 /**
882 check for global access and give descriptive error message if it fails.
833f2639 883
9cb44948
AM
884@@ -5406,6 +5631,10 @@
885 reset_dynamic(&thd->user_var_events);
886 thd->user_var_events_alloc= thd->mem_root;
833f2639 887 }
9cb44948
AM
888+
889+ thd->updated_row_count=0;
890+ thd->busy_time=0;
891+
892 thd->clear_error();
893 thd->main_da.reset_diagnostics_area();
894 thd->total_warn_count=0; // Warnings for this query
895@@ -5585,6 +5814,16 @@
833f2639
ER
896 DBUG_ENTER("mysql_parse");
897
898 DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
899+
900+ int start_time_error = 0;
901+ int end_time_error = 0;
902+ struct timeval start_time, end_time;
903+ double start_usecs = 0;
904+ double end_usecs = 0;
905+ // Gets the start time, in order to measure how long this command takes.
906+ if (!(start_time_error = gettimeofday(&start_time, NULL))) {
907+ start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec;
908+ }
909
910 /*
911 Warning.
9cb44948 912@@ -5674,6 +5913,27 @@
833f2639
ER
913 *found_semicolon= NULL;
914 }
915
916+ // Gets the end time.
917+ if (!(end_time_error = gettimeofday(&end_time, NULL))) {
918+ end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec;
919+ }
920+
921+ // Calculates the difference between the end and start times.
922+ if (end_usecs >= start_usecs && !start_time_error && !end_time_error) {
923+ thd->busy_time = (end_usecs - start_usecs) / 1000000;
924+ // In case there are bad values, 2629743 is the #seconds in a month.
925+ if (thd->busy_time > 2629743) {
926+ thd->busy_time = 0;
927+ }
928+ } else {
929+ // end time went back in time, or gettimeofday() failed.
930+ thd->busy_time = 0;
931+ }
932+
933+ // Updates THD stats and the global user stats.
934+ thd->update_stats();
935+ update_global_user_stats(thd);
936+
937 DBUG_VOID_RETURN;
938 }
939
9cb44948 940@@ -6256,6 +6516,7 @@
833f2639
ER
941 tables->lock_type= lock_type;
942 tables->updating= for_update;
943 }
944+
945 DBUG_VOID_RETURN;
946 }
947
9cb44948 948@@ -6623,6 +6884,21 @@
833f2639 949 #endif
9cb44948
AM
950 if (options & REFRESH_USER_RESOURCES)
951 reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
952+ if (options & REFRESH_TABLE_STATS)
953+ {
954+ pthread_mutex_lock(&LOCK_global_table_stats);
955+ free_global_table_stats();
956+ init_global_table_stats();
957+ pthread_mutex_unlock(&LOCK_global_table_stats);
958+ }
959+ if (options & REFRESH_INDEX_STATS)
960+ {
961+ pthread_mutex_lock(&LOCK_global_index_stats);
962+ free_global_index_stats();
963+ init_global_index_stats();
964+ pthread_mutex_unlock(&LOCK_global_index_stats);
965+ }
966+
833f2639
ER
967 *write_to_binlog= tmp_write_to_binlog;
968 return result;
969 }
9cb44948
AM
970diff -r ab66c8ca382a sql/sql_show.cc
971--- a/sql/sql_show.cc Thu Sep 04 12:08:00 2008 -0700
972+++ b/sql/sql_show.cc Thu Sep 04 12:12:44 2008 -0700
973@@ -2239,6 +2239,90 @@
833f2639
ER
974 DBUG_RETURN(FALSE);
975 }
976
9cb44948 977+
833f2639
ER
978+int fill_schema_user_stats(THD* thd, TABLE_LIST* tables, COND* cond)
979+{
980+ TABLE *table= tables->table;
981+ DBUG_ENTER("fill_schema_user_stats");
982+
983+ set_concurrent_connections_stats();
984+
985+ pthread_mutex_lock(&LOCK_global_user_stats);
986+ for (int i = 0; i < global_user_stats.records; ++i) {
987+ restore_record(table, s->default_values);
988+ USER_STATS *user_stats = (USER_STATS*)hash_element(&global_user_stats, i);
989+ table->field[0]->store(user_stats->user, strlen(user_stats->user), system_charset_info);
990+ table->field[1]->store((longlong)user_stats->total_connections, TRUE);
991+ table->field[2]->store((longlong)user_stats->concurrent_connections, TRUE);
992+ table->field[3]->store((longlong)user_stats->connected_time, TRUE);
993+ table->field[4]->store((longlong)user_stats->busy_time, TRUE);
994+ table->field[5]->store((longlong)user_stats->rows_fetched, TRUE);
995+ table->field[6]->store((longlong)user_stats->rows_updated, TRUE);
996+ table->field[7]->store((longlong)user_stats->select_commands, TRUE);
997+ table->field[8]->store((longlong)user_stats->update_commands, TRUE);
998+ table->field[9]->store((longlong)user_stats->other_commands, TRUE);
999+ table->field[10]->store((longlong)user_stats->commit_trans, TRUE);
1000+ table->field[11]->store((longlong)user_stats->rollback_trans, TRUE);
1001+
1002+ if (schema_table_store_record(thd, table))
1003+ {
1004+ VOID(pthread_mutex_unlock(&LOCK_global_user_stats));
1005+ DBUG_RETURN(1);
1006+ }
1007+ }
1008+ pthread_mutex_unlock(&LOCK_global_user_stats);
1009+ DBUG_RETURN(0);
1010+}
1011+
9cb44948 1012+
833f2639
ER
1013+int fill_schema_table_stats(THD* thd, TABLE_LIST* tables, COND* cond)
1014+{
1015+ TABLE *table= tables->table;
1016+ DBUG_ENTER("fill_schema_table_stats");
1017+
1018+ pthread_mutex_lock(&LOCK_global_table_stats);
1019+ for (int i = 0; i < global_table_stats.records; ++i) {
1020+ restore_record(table, s->default_values);
1021+ TABLE_STATS *table_stats =
1022+ (TABLE_STATS*)hash_element(&global_table_stats, i);
1023+ table->field[0]->store(table_stats->table, strlen(table_stats->table), system_charset_info);
1024+ table->field[1]->store((longlong)table_stats->rows_read, TRUE);
1025+ table->field[2]->store((longlong)table_stats->rows_changed, TRUE);
1026+ table->field[3]->store((longlong)table_stats->rows_changed_x_indexes, TRUE);
1027+
1028+ if (schema_table_store_record(thd, table))
1029+ {
1030+ VOID(pthread_mutex_unlock(&LOCK_global_table_stats));
1031+ DBUG_RETURN(1);
1032+ }
1033+ }
1034+ pthread_mutex_unlock(&LOCK_global_table_stats);
1035+ DBUG_RETURN(0);
1036+}
1037+
9cb44948 1038+
833f2639
ER
1039+int fill_schema_index_stats(THD* thd, TABLE_LIST* tables, COND* cond)
1040+{
1041+ TABLE *table= tables->table;
1042+ DBUG_ENTER("fill_schema_index_stats");
1043+
1044+ pthread_mutex_lock(&LOCK_global_index_stats);
1045+ for (int i = 0; i < global_index_stats.records; ++i) {
1046+ restore_record(table, s->default_values);
1047+ INDEX_STATS *index_stats =
1048+ (INDEX_STATS*)hash_element(&global_index_stats, i);
1049+ table->field[0]->store(index_stats->index, strlen(index_stats->index), system_charset_info);
1050+ table->field[1]->store((longlong)index_stats->rows_read, TRUE);
1051+
1052+ if (schema_table_store_record(thd, table))
1053+ {
1054+ VOID(pthread_mutex_unlock(&LOCK_global_index_stats));
1055+ DBUG_RETURN(1);
1056+ }
1057+ }
1058+ pthread_mutex_unlock(&LOCK_global_index_stats);
1059+ DBUG_RETURN(0);
1060+}
833f2639
ER
1061
1062 /* collect status for all running threads */
1063
9cb44948
AM
1064@@ -6565,6 +6649,38 @@
1065 {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
833f2639
ER
1066 };
1067
1068+ST_FIELD_INFO user_stats_fields_info[]=
1069+{
9cb44948
AM
1070+ {"USER", 16, MYSQL_TYPE_STRING, 0, 0, "User", SKIP_OPEN_TABLE},
1071+ {"TOTAL_CONNECTIONS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Total_connections", SKIP_OPEN_TABLE},
1072+ {"CONCURRENT_CONNECTIONS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Concurrent_connections", SKIP_OPEN_TABLE},
1073+ {"CONNECTED_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Connected_time", SKIP_OPEN_TABLE},
1074+ {"BUSY_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Busy_time", SKIP_OPEN_TABLE},
1075+ {"ROWS_FETCHED", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_fetched", SKIP_OPEN_TABLE},
1076+ {"ROWS_UPDATED", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_updated", SKIP_OPEN_TABLE},
1077+ {"SELECT_COMMANDS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Select_commands", SKIP_OPEN_TABLE},
1078+ {"UPDATE_COMMANDS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Update_commands", SKIP_OPEN_TABLE},
1079+ {"OTHER_COMMANDS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Other_commands", SKIP_OPEN_TABLE},
1080+ {"COMMIT_TRANSACTIONS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Commit_transactions", SKIP_OPEN_TABLE},
1081+ {"ROLLBACK_TRANSACTIONS", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rollback_transactions", SKIP_OPEN_TABLE},
1082+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
833f2639
ER
1083+};
1084+
1085+ST_FIELD_INFO table_stats_fields_info[]=
1086+{
9cb44948
AM
1087+ {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_name", SKIP_OPEN_TABLE},
1088+ {"ROWS_READ", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read", SKIP_OPEN_TABLE},
1089+ {"ROWS_CHANGED", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed", SKIP_OPEN_TABLE},
1090+ {"ROWS_CHANGED_INDEXES", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_changed_x_#indexes", SKIP_OPEN_TABLE},
1091+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
833f2639
ER
1092+};
1093+
1094+ST_FIELD_INFO index_stats_fields_info[]=
1095+{
9cb44948
AM
1096+ {"INDEX_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Index_name", SKIP_OPEN_TABLE},
1097+ {"ROWS_READ", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Rows_read", SKIP_OPEN_TABLE},
1098+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
833f2639
ER
1099+};
1100
1101 /*
1102 Description of ST_FIELD_INFO in table.h
9cb44948
AM
1103@@ -6601,6 +6717,8 @@
1104 fill_status, make_old_format, 0, -1, -1, 0, 0},
1105 {"GLOBAL_VARIABLES", variables_fields_info, create_schema_table,
1106 fill_variables, make_old_format, 0, -1, -1, 0, 0},
833f2639 1107+ {"INDEX_STATISTICS", index_stats_fields_info, create_schema_table,
9cb44948 1108+ fill_schema_index_stats, make_old_format, 0, -1, -1, 0, 0},
833f2639 1109 {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
9cb44948
AM
1110 get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
1111 OPEN_TABLE_ONLY},
1112@@ -6642,11 +6760,15 @@
1113 get_all_tables, make_table_names_old_format, 0, 1, 2, 1, 0},
833f2639 1114 {"TABLE_PRIVILEGES", table_privileges_fields_info, create_schema_table,
9cb44948 1115 fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
833f2639 1116+ {"TABLE_STATISTICS", table_stats_fields_info, create_schema_table,
9cb44948 1117+ fill_schema_table_stats, make_old_format, 0, -1, -1, 0, 0},
833f2639 1118 {"TRIGGERS", triggers_fields_info, create_schema_table,
9cb44948
AM
1119 get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
1120 OPEN_TABLE_ONLY},
833f2639 1121 {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
9cb44948 1122 fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
833f2639 1123+ {"USER_STATISTICS", user_stats_fields_info, create_schema_table,
9cb44948 1124+ fill_schema_user_stats, make_old_format, 0, -1, -1, 0, 0},
833f2639 1125 {"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
9cb44948 1126 make_old_format, 0, -1, -1, 1, 0},
833f2639 1127 {"VIEWS", view_fields_info, create_schema_table,
9cb44948
AM
1128diff -r ab66c8ca382a sql/sql_update.cc
1129--- a/sql/sql_update.cc Thu Sep 04 12:08:00 2008 -0700
1130+++ b/sql/sql_update.cc Thu Sep 04 12:12:45 2008 -0700
1131@@ -816,6 +816,7 @@
1132 thd->row_count_func=
833f2639 1133 (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
9cb44948 1134 my_ok(thd, (ulong) thd->row_count_func, id, buff);
833f2639 1135+ thd->updated_row_count += thd->row_count_func;
9cb44948 1136 DBUG_PRINT("info",("%ld records updated", (long) updated));
833f2639
ER
1137 }
1138 thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
9cb44948
AM
1139@@ -2007,5 +2008,6 @@
1140 thd->row_count_func=
833f2639 1141 (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
9cb44948 1142 ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
833f2639 1143+ thd->updated_row_count += thd->row_count_func;
9cb44948 1144 DBUG_RETURN(FALSE);
833f2639 1145 }
9cb44948
AM
1146diff -r ab66c8ca382a sql/sql_yacc.yy
1147--- a/sql/sql_yacc.yy Thu Sep 04 12:08:00 2008 -0700
1148+++ b/sql/sql_yacc.yy Thu Sep 04 12:12:45 2008 -0700
1149@@ -737,6 +737,7 @@
833f2639
ER
1150 %token IMPORT
1151 %token INDEXES
1152 %token INDEX_SYM
1153+%token INDEX_STATS_SYM
1154 %token INFILE
9cb44948
AM
1155 %token INITIAL_SIZE_SYM
1156 %token INNER_SYM /* SQL-2003-R */
1157@@ -1025,6 +1026,7 @@
1158 %token TABLE_REF_PRIORITY
1159 %token TABLE_SYM /* SQL-2003-R */
1160 %token TABLE_CHECKSUM_SYM
833f2639 1161+%token TABLE_STATS_SYM
9cb44948 1162 %token TEMPORARY /* SQL-2003-N */
833f2639
ER
1163 %token TEMPTABLE_SYM
1164 %token TERMINATED
9cb44948 1165@@ -1070,6 +1072,7 @@
833f2639 1166 %token UPGRADE_SYM
9cb44948
AM
1167 %token USAGE /* SQL-2003-N */
1168 %token USER /* SQL-2003-R */
833f2639
ER
1169+%token USER_STATS_SYM
1170 %token USE_FRM
1171 %token USE_SYM
9cb44948
AM
1172 %token USING /* SQL-2003-R */
1173@@ -9353,6 +9356,27 @@
833f2639 1174 {
9cb44948 1175 Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
833f2639
ER
1176 }
1177+ | USER_STATS_SYM wild_and_where
1178+ {
9cb44948
AM
1179+ LEX *lex= Lex;
1180+ lex->sql_command= SQLCOM_SHOW_USER_STATS;
1181+ if (prepare_schema_table(YYTHD, lex, 0, SCH_USER_STATS))
1182+ MYSQL_YYABORT;
833f2639
ER
1183+ }
1184+ | TABLE_STATS_SYM wild_and_where
1185+ {
9cb44948
AM
1186+ LEX *lex= Lex;
1187+ lex->sql_command= SQLCOM_SHOW_TABLE_STATS;
1188+ if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_STATS))
1189+ MYSQL_YYABORT;
833f2639
ER
1190+ }
1191+ | INDEX_STATS_SYM wild_and_where
1192+ {
9cb44948
AM
1193+ LEX *lex= Lex;
1194+ lex->sql_command= SQLCOM_SHOW_INDEX_STATS;
1195+ if (prepare_schema_table(YYTHD, lex, 0, SCH_INDEX_STATS))
1196+ MYSQL_YYABORT;
833f2639 1197+ }
9cb44948
AM
1198 | CREATE PROCEDURE sp_name
1199 {
1200 LEX *lex= Lex;
1201@@ -9567,6 +9591,10 @@
1202 { Lex->type|= REFRESH_DES_KEY_FILE; }
1203 | RESOURCES
1204 { Lex->type|= REFRESH_USER_RESOURCES; }
1205+ | TABLE_STATS_SYM
1206+ { Lex->type|= REFRESH_TABLE_STATS; }
1207+ | INDEX_STATS_SYM
1208+ { Lex->type|= REFRESH_INDEX_STATS; }
1209 ;
833f2639
ER
1210
1211 opt_table_list:
9cb44948
AM
1212diff -r ab66c8ca382a sql/structs.h
1213--- a/sql/structs.h Thu Sep 04 12:08:00 2008 -0700
1214+++ b/sql/structs.h Thu Sep 04 12:12:45 2008 -0700
1215@@ -226,6 +226,28 @@
1216 /* Maximum amount of resources which account is allowed to consume. */
1217 USER_RESOURCES user_resources;
833f2639 1218 } USER_CONN;
9cb44948 1219+
833f2639
ER
1220+typedef struct st_user_stats {
1221+ char user[USERNAME_LENGTH + 1];
1222+ uint total_connections;
1223+ uint concurrent_connections;
1224+ time_t connected_time; // in seconds
1225+ double busy_time; // in seconds
1226+ ha_rows rows_fetched, rows_updated;
1227+ ulonglong select_commands, update_commands, other_commands;
1228+ ulonglong commit_trans, rollback_trans;
1229+} USER_STATS;
1230+
1231+typedef struct st_table_stats {
1232+ char table[NAME_LEN * 2 + 2]; // [db] + '.' + [table] + '\0'
1233+ ulonglong rows_read, rows_changed;
1234+ ulonglong rows_changed_x_indexes;
1235+} TABLE_STATS;
1236+
1237+typedef struct st_index_stats {
1238+ char index[NAME_LEN * 3 + 3]; // [db] + '.' + [table] + '.' + [index] + '\0'
1239+ ulonglong rows_read;
1240+} INDEX_STATS;
9cb44948 1241
833f2639
ER
1242 /* Bits in form->update */
1243 #define REG_MAKE_DUPP 1 /* Make a copy of record when read */
9cb44948
AM
1244diff -r ab66c8ca382a sql/table.h
1245--- a/sql/table.h Thu Sep 04 12:08:00 2008 -0700
1246+++ b/sql/table.h Thu Sep 04 12:12:45 2008 -0700
1247@@ -824,6 +824,7 @@
1248 SCH_FILES,
1249 SCH_GLOBAL_STATUS,
1250 SCH_GLOBAL_VARIABLES,
833f2639
ER
1251+ SCH_INDEX_STATS,
1252 SCH_KEY_COLUMN_USAGE,
1253 SCH_OPEN_TABLES,
9cb44948
AM
1254 SCH_PARTITIONS,
1255@@ -842,8 +843,10 @@
833f2639
ER
1256 SCH_TABLE_CONSTRAINTS,
1257 SCH_TABLE_NAMES,
1258 SCH_TABLE_PRIVILEGES,
1259+ SCH_TABLE_STATS,
1260 SCH_TRIGGERS,
1261 SCH_USER_PRIVILEGES,
1262+ SCH_USER_STATS,
1263 SCH_VARIABLES,
1264 SCH_VIEWS
1265 };
9cb44948
AM
1266diff -r ab66c8ca382a storage/innobase/handler/ha_innodb.cc
1267--- a/storage/innobase/handler/ha_innodb.cc Thu Sep 04 12:08:00 2008 -0700
1268+++ b/storage/innobase/handler/ha_innodb.cc Thu Sep 04 12:12:45 2008 -0700
1269@@ -3925,6 +3925,8 @@
1270
1271 error = row_insert_for_mysql((byte*) record, prebuilt);
1272
1273+ if (error == DB_SUCCESS) rows_changed++;
1274+
1275 /* Handle duplicate key errors */
1276 if (auto_inc_used) {
1277 ulint err;
1278@@ -4001,6 +4003,8 @@
1279 break;
1280 }
1281 }
1282+
1283+ if (error == DB_SUCCESS) rows_changed++;
1284
1285 innodb_srv_conc_exit_innodb(prebuilt->trx);
1286
1287@@ -4647,6 +4651,8 @@
1288 ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
1289 match_mode, 0);
1290
1291+ if (error == DB_SUCCESS) rows_changed++;
1292+
1293 innodb_srv_conc_exit_innodb(prebuilt->trx);
1294 } else {
1295
1296@@ -4193,6 +4193,9 @@
1297 if (ret == DB_SUCCESS) {
1298 error = 0;
1299 table->status = 0;
1300+ rows_read++;
1301+ if (active_index >= 0 && active_index < MAX_KEY)
1302+ index_rows_read[active_index]++;
1303
1304 } else if (ret == DB_RECORD_NOT_FOUND) {
1305 error = HA_ERR_KEY_NOT_FOUND;
1306@@ -4366,6 +4369,9 @@
1307 if (ret == DB_SUCCESS) {
1308 error = 0;
1309 table->status = 0;
1310+ rows_read++;
1311+ if (active_index >= 0 && active_index < MAX_KEY)
1312+ index_rows_read[active_index]++;
1313
1314 } else if (ret == DB_RECORD_NOT_FOUND) {
1315 error = HA_ERR_END_OF_FILE;
1316diff -r ab66c8ca382a storage/myisam/ha_myisam.cc
1317--- a/storage/myisam/ha_myisam.cc Thu Sep 04 12:08:00 2008 -0700
1318+++ b/storage/myisam/ha_myisam.cc Thu Sep 04 12:12:45 2008 -0700
1319@@ -738,7 +738,9 @@
1320 if ((error= update_auto_increment()))
1321 return error;
1322 }
1323- return mi_write(file,buf);
1324+ int error=mi_write(file,buf);
1325+ if (!error) rows_changed++;
1326+ return error;
1327 }
1328
1329 int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
1330@@ -1589,13 +1591,17 @@
1331 ha_statistic_increment(&SSV::ha_update_count);
1332 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1333 table->timestamp_field->set_time();
1334- return mi_update(file,old_data,new_data);
1335+ int error=mi_update(file,old_data,new_data);
1336+ if (!error) rows_changed++;
1337+ return error;
1338 }
1339
1340 int ha_myisam::delete_row(const uchar *buf)
1341 {
1342 ha_statistic_increment(&SSV::ha_delete_count);
1343- return mi_delete(file,buf);
1344+ int error=mi_delete(file,buf);
1345+ if (!error) rows_changed++;
1346+ return error;
1347 }
1348
1349 int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1350@@ -1606,6 +1612,13 @@
1351 ha_statistic_increment(&SSV::ha_read_key_count);
1352 int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1353 table->status=error ? STATUS_NOT_FOUND: 0;
1354+ if (!error) {
1355+ rows_read++;
1356+
1357+ int inx = (active_index == -1) ? file->lastinx : active_index;
1358+ if (inx >= 0 && inx < MAX_KEY)
1359+ index_rows_read[inx]++;
1360+ }
1361 return error;
1362 }
1363
1364@@ -1616,6 +1629,14 @@
1365 ha_statistic_increment(&SSV::ha_read_key_count);
1366 int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1367 table->status=error ? STATUS_NOT_FOUND: 0;
1368+ if (!error) {
1369+ rows_read++;
1370+
1371+// int inx = (active_index == -1) ? file->lastinx : active_index;
1372+ int inx = index;
1373+ if (inx >= 0 && inx < MAX_KEY)
1374+ index_rows_read[inx]++;
1375+ }
1376 return error;
1377 }
1378
1379@@ -1637,6 +1658,13 @@
1380 ha_statistic_increment(&SSV::ha_read_next_count);
1381 int error=mi_rnext(file,buf,active_index);
1382 table->status=error ? STATUS_NOT_FOUND: 0;
1383+ if (!error) {
1384+ rows_read++;
1385+
1386+ int inx = (active_index == -1) ? file->lastinx : active_index;
1387+ if (inx >= 0 && inx < MAX_KEY)
1388+ index_rows_read[inx]++;
1389+ }
1390 return error;
1391 }
1392
1393@@ -1646,6 +1674,13 @@
1394 ha_statistic_increment(&SSV::ha_read_prev_count);
1395 int error=mi_rprev(file,buf, active_index);
1396 table->status=error ? STATUS_NOT_FOUND: 0;
1397+ if (!error) {
1398+ rows_read++;
1399+
1400+ int inx = (active_index == -1) ? file->lastinx : active_index;
1401+ if (inx >= 0 && inx < MAX_KEY)
1402+ index_rows_read[inx]++;
1403+ }
1404 return error;
1405 }
1406
1407@@ -1655,6 +1690,13 @@
1408 ha_statistic_increment(&SSV::ha_read_first_count);
1409 int error=mi_rfirst(file, buf, active_index);
1410 table->status=error ? STATUS_NOT_FOUND: 0;
1411+ if (!error) {
1412+ rows_read++;
1413+
1414+ int inx = (active_index == -1) ? file->lastinx : active_index;
1415+ if (inx >= 0 && inx < MAX_KEY)
1416+ index_rows_read[inx]++;
1417+ }
1418 return error;
1419 }
1420
1421@@ -1664,6 +1706,13 @@
1422 ha_statistic_increment(&SSV::ha_read_last_count);
1423 int error=mi_rlast(file, buf, active_index);
1424 table->status=error ? STATUS_NOT_FOUND: 0;
1425+ if (!error) {
1426+ rows_read++;
1427+
1428+ int inx = (active_index == -1) ? file->lastinx : active_index;
1429+ if (inx >= 0 && inx < MAX_KEY)
1430+ index_rows_read[inx]++;
1431+ }
1432 return error;
1433 }
1434
1435@@ -1679,6 +1728,20 @@
1436 error= mi_rnext_same(file,buf);
1437 } while (error == HA_ERR_RECORD_DELETED);
1438 table->status=error ? STATUS_NOT_FOUND: 0;
1439+ if (!error) {
1440+ rows_read++;
1441+
1442+ int inx = (active_index == -1) ? file->lastinx : active_index;
1443+ if (inx >= 0 && inx < MAX_KEY)
1444+ index_rows_read[inx]++;
1445+ }
1446+ if (!error) {
1447+ rows_read++;
1448+
1449+ int inx = (active_index == -1) ? file->lastinx : active_index;
1450+ if (inx >= 0 && inx < MAX_KEY)
1451+ index_rows_read[inx]++;
1452+ }
1453 return error;
1454 }
1455
1456@@ -1695,6 +1758,7 @@
1457 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1458 int error=mi_scan(file, buf);
1459 table->status=error ? STATUS_NOT_FOUND: 0;
1460+ if (!error) rows_read++;
1461 return error;
1462 }
1463
1464@@ -1708,6 +1772,7 @@
1465 ha_statistic_increment(&SSV::ha_read_rnd_count);
1466 int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1467 table->status=error ? STATUS_NOT_FOUND: 0;
1468+ if (!error) rows_read++;
1469 return error;
1470 }
1471
This page took 0.526405 seconds and 4 git commands to generate.