应元同学说要系统介绍一下THD类。我表示这个类太大,如果只是将字段意义依次列出意义不大,最好是碰到问题将相关的字段再说明,能关联更多信息。最近的一个patch中刚好碰到user_connect(好吧,是误用), 就介绍一下。
1、 字段说明
THD::user_connect字段是USER_CONN类型,声明在sql/structs.h. 其作用是记录当前连接用户的信息。结构如下:
typedef struct user_conn {
char *user;
char *host;
ulonglong reset_utime;
uint connections;
uint conn_per_hour, updates, questions;
USER_RESOURCES user_resources;
} USER_CONN;
可以看到,其中保存了用户名、客户端host信息,还有本用户的更新数、连接数等。
与之配套的,是一个hash结构hash_user_connections,hash_key中包含user和host。因此相同user &host的连接共享同一个USER_CONN.
2、数据源
conn_per_hour, updates, questions是当前连接对应的用户的实时统计信息。user_resources为元数据,来源于表mysql.user.
如:在localhost用root账户登录,update mysql.user set max_updates =2 where user=’root’; flush privileges; (必须flush后才生效)。则此账号最多只能执行2个更新操作(不局限于update)。
3、相关问题
a) hash_user_connections为内存结构,因此统计信息重启后并不保存;
b) 如果达到某个统计值达到上限,比如更新数,如何清空?
实际上并没有提供单独清空某个统计值的接口。但在执行 flush privileges和flush user_resources时,会将所有的统计值清空。对应被调用的函数为 reset_mqh (sql/sql_connect.cc).
/* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */ for (uint idx=0;idx < hash_user_connections.records; idx++) { USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, idx); if (get_them) get_mqh(uc->user,uc->host,uc); uc->questions=0; uc->updates=0; uc->conn_per_hour=0; }
c) 是否所有的连接都会设置user_connect?
实际上,由于mysql.user里面的最后四个字段往往是被设置为默认的0。是否设置user_connect就取决于配置参数max_user_connections。 若为0,则该server的所有连接,都不设置user_connect.。估计是MySQL考虑到所有这些值都为0,不需要记录统计信息。实现策略的代码为
if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || max_user_connections) && get_or_create_user_conn(thd, (opt_old_style_user_limits ? thd->main_security_ctx.user : thd->main_security_ctx.priv_user), (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : thd->main_security_ctx.priv_host), &ur)) { /* The error is set by get_or_create_user_conn(). */ DBUG_RETURN(1); }
可以看到,如果前面列出的所有值都为0,则不执行函数get_or_create_user_conn。
thd->ser_connect实例在此函数中创建。