MySQL ошибка 1436: переполнение стека потока, с простым запросом - PullRequest
28 голосов
/ 11 января 2012

Я делаю очень простое обновление таблицы, которое также запускает очень простой триггер, и оно выдает мне ошибку

#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 ;

Почему отображается эта ошибка?Это не так, как будто есть какой-то тяжелый запрос.Также обратите внимание, что база данных почти пуста, всего 2 строки в community_fields_values и никаких строк в user_field_log

версии MySQL: 5.1.44

Ответы [ 2 ]

54 голосов
/ 19 января 2012

1436 - переполнение стека потоков: используется 6136 байт из стека 131072 байт и необходимо 128000 байт.

Ошибка 1436 соответствует ER_STACK_OVERRUN_NEED_MORE в коде mysql 5.1:

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.

Вызов check_stack_overrun (), который пытается зарезервировать 128000 байт, происходит из:

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' реализована в C как 'my_thread_stack_size' в sql / mysqld.cc:

  {"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

Таким образом, по умолчанию размер стека должен составлять 192 КБ (32 бита) или 256 КБ (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

В моей системе я получил 256 КБ на 64-битной платформе.

Если естьэто разные значения, может быть, кто-то собирает сервер с разными параметрами компиляции, такими как -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 (теоретически, читая код, я сам никогда ее не видел).

Надеюсь, это ответит на вопрос.

С уважением, - МаркAlff

Обновление (2014-03-11), чтобы сделать "как исправить" более очевидным.

По всей вероятности, это значение по умолчанию для файла thread_stackбыло изменено в файле my.cnf.

Как исправить это тривиально, найдите, где в файле my.cnf задано значение thread_stack, и либо удалите настройку (доверяя коду сервера обеспечить достойное значение по умолчанию)значение, чтобы это не повторилось в следующий раз) или увеличьте размер стека.

33 голосов
/ 11 января 2012

Хотя это не решение, но быстрое решение может состоять в том, чтобы увеличить размер thread_stack, увеличив его в my.cnf:

thread_stack = 256K

Как указал пользователь "foo", размещение всего кода триггера может быть более полезным для выявления реальной проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...