web-dev-qa-db-ja.com

MySQLエラー1436:単純なクエリでのスレッドスタックオーバーラン

テーブルで非常に簡単な更新を行っていますが、これも非常に簡単なトリガーをトリガーし、エラーが発生します

#1436 - Thread stack overrun:  6136 bytes used of a 131072 byte stack, and 128000 bytes needed.

私が実行するクエリ:

UPDATE field_values SET value = 'asaf' WHERE field_values.id =1

値フィールドはtextフィールドです。したがって、理論的には静かに大きくなる可能性があります。この状況ではそうではありません。

実行されるトリガーは次のとおりです。

DELIMITER $$
    CREATE TRIGGER field_value_update_trigger BEFORE UPDATE ON community_fields_values
    FOR EACH ROW BEGIN
      INSERT INTO user_field_log (user_id, field_id, value) VALUES (NEW.user_id, NEW.field_id, NEW.value);
    END;
$$
DELIMITER ;

このエラーが表示されるのはなぜですか?重いクエリが関係しているわけではありません。また、データベースはほとんど空で、community_fields_valuesには2行しかなく、user_field_logには行がないことに注意してください。

MySQLバージョン:5.1.44

29
Rene Pot

1436-スレッドスタックオーバーラン:131072バイトスタックのうち6136バイトが使用され、128000バイトが必要です。

エラー1436は、mysql 5.1コードのER_STACK_OVERRUN_NEED_MOREに対応しています。

malff@linux-8edv:include> pwd
/home/malff/BZR_TREE/mysql-5.1/include
malff@linux-8edv:include> grep 1436 mysqld_error.h
#define ER_STACK_OVERRUN_NEED_MORE 1436

表示されたエラーを出力するコードは、sql/sql_parse.cc、関数check_stack_overrun()にあります。

bool check_stack_overrun(THD *thd, long margin,
                         uchar *buf __attribute__((unused)))
{
  long stack_used;
  DBUG_ASSERT(thd == current_thd);
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) (my_thread_stack_size - margin))
  {
    char ebuff[MYSQL_ERRMSG_SIZE];
    my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
                stack_used, my_thread_stack_size, margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));

表示された値から、マージンは128000、my_thread_stack_sizeは131072です。

128000バイトを予約しようとするcheck_stack_overrun()の唯一の呼び出しは、次のものからです。

bool
sp_head::execute(THD *thd)
{
  /* Use some extra margin for possible SP recursion and functions */
  if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
    DBUG_RETURN(TRUE);

STACK_MIN_SIZEの値は16000です。

malff@linux-8edv:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
malff@linux-8edv:sql> grep STACK_MIN_SIZE *.h
mysql_priv.h:#define STACK_MIN_SIZE          16000   // Abort if less stack during eval.

これまでのところ、すべてはサーバーに対して期待どおりに機能します。

  • コードは、sp_head :: executeで実装されるトリガーを実行します。
  • mySQLランタイムは、スタック上に少なくとも128000バイトがあることを確認します
  • このチェックは(正しく)失敗し、トリガーの実行はエラーで終了します。

MySQLトリガーの実行に必要なスタックの量は、トリガーの複雑さ自体や、関係するテーブルのコンテンツ/構造に依存しません。

realの質問は、thread_stackが128K(131072)である理由です。

「thread_stack」という名前のサーバー変数は、sql/mysqld.ccの「my_thread_stack_size」としてCに実装されています。

  {"thread_stack", OPT_THREAD_STACK,
   "The stack size for each thread.", &my_thread_stack_size,
   &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
   1024L*128L, ULONG_MAX, 0, 1024, 0},

1024L * 128Lは、このパラメーターの最小値です。デフォルト値はDEFAULT_THREAD_STACKで、include/my_pthread.hで定義されています。

#ifndef DEFAULT_THREAD_STACK
#if SIZEOF_CHARP > 4
/*
  MySQL can survive with 32K, but some glibc libraries require > 128K stack
  To resolve hostnames. Also recursive stored procedures needs stack.
*/
#define DEFAULT_THREAD_STACK    (256*1024L)
#else
#define DEFAULT_THREAD_STACK    (192*1024)
#endif
#endif

そのため、デフォルトでは、スタックサイズは192K(32ビット)または256K(64ビットアーキテクチャ)である必要があります。

最初に、mysqldバイナリがどのようにコンパイルされたかを確認して、デフォルト値を確認します。

malff@linux-8edv:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
malff@linux-8edv:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack
...
  --thread_stack=#    The stack size for each thread.
thread_stack                      262144

私のシステムでは、64ビットプラットフォームで256Kを取得しました。

異なる値がある場合、誰かが-DDEFAULT_THREAD_STACKなどの異なるコンパイルオプションを使用してサーバーを構築する(またはソースを変更する)場合があります。

次に、my.cnfで、構成ファイル自体で提供されているデフォルト値を確認します。値をthread_stackに明示的に(および低い値で)設定する行は、間違いなくエラーを引き起こします。

最後に、サーバーログファイルで次のようなエラーを確認します(sql/mysqld.ccを参照)。

sql_print_warning("Asked for %lu thread stack, but got %ld",
                  my_thread_stack_size, (long) stack_size);

サーバーコードは以下を呼び出します。

  • スタックサイズを設定するpthread_attr_setstacksize()
  • pthread_attr_getstacksize()を使用して、スレッドが実際に持っているスタックの量を確認し、pthreadライブラリの使用量が少ない場合はログにエラーが表示されます。

端的に言えば、サーバーに付属のデフォルト値と比較してthread_stackが小さすぎるため、エラーが発生します。これは起こる可能性があります:

  • さまざまなコンパイルオプションを使用して、サーバーのカスタムビルドを行う場合
  • my.cnfファイルのデフォルト値を変更するとき
  • pthreadライブラリ自体で問題が発生した場合(理論的にはコードを読んでから、自分で見たことがない)。

これで質問に答えていただければ幸いです。

よろしく-マーク・アルフ

更新(2014-03-11)、「修正方法」をより明確にするため。

ほとんどの場合、my.cnfファイルでthread_stackファイルのデフォルト値が変更されています。

それを修正する方法は簡単で、my.cnfファイルでthread_stackが設定されている場所を見つけ、設定を削除する(適切なデフォルト値を提供するためにサーバーコードを信頼するため、次回は再び発生しません)か、スタックを増やしますサイズ。

55
Marc Alff

解決策ではありませんが、簡単な解決策は、my.cnfでthread_stackのサイズを増加させることです。

thread_stack = 256K

ユーザー "foo"が指摘したように、実際の問題を検出するには、トリガーコード全体をポストする方がより役立つ場合があります。

33
JayTaph