]>
Commit | Line | Data |
---|---|---|
9cb44948 AM |
1 | diff -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 | 13 | diff -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 |
23 | diff -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 |
157 | diff -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) | |
217 | diff -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 |
244 | diff -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 |
280 | diff -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 |
363 | diff -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); |
389 | diff -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 |
457 | diff -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 |
515 | diff -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 | ||
556 | diff -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 |
575 | diff -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 |
586 | diff -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[]= {" ... | |
598 | diff -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 |
970 | diff -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 |
1128 | diff -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 |
1146 | diff -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 |
1212 | diff -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 |
1244 | diff -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 |
1266 | diff -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; | |
1316 | diff -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 |