TL;DR
- 1SQLのサイズ上限は、max_allowed_packetとnet_buffer_lengthで制御される。
- max_allowed_packetはグローバルにデフォルト値を持ち、コネクション確立時にセッションにコピーされ、セッション変数は読み込み専用である。(セッションに適用するにはconnectなど再接続が必要)
- net_buffer_lengthはグローバルにデフォルト値を持ち、コネクション確立時にセッションにコピーされ、セッション変数も変更可能である。
- net_buffer_length => max_allowed_packetの場合、net_buffer_lengthが1SQLの上限値になる。
- net_buffer_length < max_allowed_packetの場合、max_allowed_packetが1SQLの上限値になる。
とまとめられているが、これは
ER_NET_PACKET_TOO_LARGE の判定は net_realloc の中で行われて、パケット < net_buffer_length のうちはnet_reallocを呼ばないのでそういう動作になるんですね! 勉強になります!— yoku0825 (@yoku0825) 2018年9月26日
ということ。
まず、
(See also Dive into MySQL Error - Speaker Deck )
max_allowed_packet
の上限に引っかかった時に出るエラーである、 “Got a packet bigger than ‘max_allowed_packet’ bytes” からたどっていくことにする。(See also Dive into MySQL Error - Speaker Deck )
ソースコードは5.7.23のものにしていますよん。
$ grep "max_allowed_packet" include/mysqld_ername.h
{ "ER_NET_PACKET_TOO_LARGE", 1153, "Got a packet bigger than \'max_allowed_packet\' bytes" },
{ "ER_TOO_LONG_STRING", 1162, "Result string is longer than \'max_allowed_packet\' bytes" },
{ "ER_WARN_ALLOWED_PACKET_OVERFLOWED", 1301, "Result of %s() was larger than max_allowed_packet (%ld) - truncated" },
MySQLへのJDBC接続で、とあるバグを踏むまでの話 -(1)「max_allowed_packet」の基本的な働き - なからなLife ではバルクインサートだったので、
ER_NET_PACKET_TOO_LARGE
の方だと思う。$ grep -r ER_NET_PACKET_TOO_LARGE . | grep -v mysql-test
./include/sql_state.h:{ ER_NET_PACKET_TOO_LARGE ,"08S01", "" },
./include/mysqld_ername.h:{ "ER_NET_PACKET_TOO_LARGE", 1153, "Got a packet bigger than \'max_allowed_packet\' bytes" },
./include/mysqld_error.h:#define ER_NET_PACKET_TOO_LARGE 1153
./libmysql/libmysql.c: else if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
./sql-common/client.c: set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
./sql-common/client.c: if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
./sql/net_serv.cc: net->last_errno= ER_NET_PACKET_TOO_LARGE;
./sql/net_serv.cc: my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
./sql/rpl_rli_pdb.cc: with error ER_NET_PACKET_TOO_LARGE.
./sql/rpl_slave.cc: mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE,
./sql/share/errmsg-utf8.txt:ER_NET_PACKET_TOO_LARGE 08S01
./include
のやつは定義系だし、 ./libmysql
, ./sql-common
のやつは ==
で比較しているのでこのエラーを受け取った後にどうするかの処理だろう。./sql/rpl_*
はレプリケーション関連なので取り敢えずパスして、 ./sql/net_serv.cc
の中で代入しているからここが本丸のような気がする。
grepで引っかかった2行は
net_realloc
という関数の中に入っていて、名前から察するにここがパケットメッセージバッファーは net_buffer_length バイトに初期化されますが、必要に応じて max_allowed_packet バイトまで大きくできます。
のパケットメッセージバッファーを大きくする処理なのであろう。
コイツが呼ばれているところを探しに行く。
$ grep -r net_realloc .
./include/mysql.h.pp:my_bool net_realloc(NET *net, size_t length);
./include/mysql_com.h:my_bool net_realloc(NET *net, size_t length);
./libmysql/libmysql.c: res= net_realloc(net, buf_length + length);
./sql/net_serv.cc:my_bool net_realloc(NET *net, size_t length)
./sql/net_serv.cc: DBUG_ENTER("net_realloc");
./sql/net_serv.cc: must match the size of the buffer allocated in net_realloc().
./sql/net_serv.cc: if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))
./libmysql
とはlibmysqlclient.so(Connector/C)のコードなので外すとするとまだ同じ ./sql/net_serv.cc
の行。開いてみると net_read_packet
の中で、「今のパケットメッセージバッファーよりもデータが大きければ net_realloc
」な記述に当たる。
というわけで、
- net_buffer_length => max_allowed_packetの場合、net_buffer_lengthが1SQLの上限値になる。
の理由は、
net_buffer_length
のサイズでアロケートされたパケットメッセージバッファが足りなくなって拡張しようとした時に初めて max_allowed_packet
と比較されてエラーに分岐するから、でした。
Cこわくないよ!
(あっdbts2018のブログがまだ下書きn
0 件のコメント :
コメントを投稿